lilact 0.2.0 → 0.2.2

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 (44) hide show
  1. package/README.md +4 -5
  2. package/dist/lilact.development.min.js +238 -278
  3. package/dist/lilact.development.min.js.map +1 -1
  4. package/dist/lilact.production.min.js +8139 -1
  5. package/dist/lilact.production.min.js.map +1 -1
  6. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  7. package/docs/classes/accessories.Suspense.html +7 -7
  8. package/docs/classes/components.Component.html +10 -10
  9. package/docs/classes/components.HTMLComponent.html +10 -10
  10. package/docs/classes/components.RootComponent.html +10 -10
  11. package/docs/functions/components.createComponent.html +1 -1
  12. package/docs/functions/components.createRoot.html +1 -1
  13. package/docs/functions/components.render.html +1 -1
  14. package/docs/functions/hooks.createContext.html +1 -1
  15. package/docs/functions/hooks.useActionState.html +3 -2
  16. package/docs/functions/hooks.useCallback.html +1 -1
  17. package/docs/functions/hooks.useContext.html +1 -1
  18. package/docs/functions/hooks.useEffect.html +4 -3
  19. package/docs/functions/hooks.useId.html +1 -1
  20. package/docs/functions/hooks.useImperativeHandle.html +1 -1
  21. package/docs/functions/hooks.useLayoutEffect.html +4 -3
  22. package/docs/functions/hooks.useLocalStorage.html +4 -3
  23. package/docs/functions/hooks.useMemo.html +4 -3
  24. package/docs/functions/hooks.useRef.html +4 -3
  25. package/docs/functions/hooks.useTransition.html +1 -1
  26. package/docs/index.html +4 -5
  27. package/docs/static/demos/pane.jsx +31 -0
  28. package/docs/static/demos/usetransition.jsx +1 -1
  29. package/docs/static/index.html +1 -0
  30. package/docs/static/lilact.development.min.js +238 -278
  31. package/docs/static/lilact.production.min.js +8139 -1
  32. package/package.json +1 -2
  33. package/root/demos/pane.jsx +31 -0
  34. package/root/demos/usetransition.jsx +1 -1
  35. package/root/index.html +1 -0
  36. package/root/lilact.development.min.js +238 -278
  37. package/root/lilact.production.min.js +8139 -1
  38. package/src/components.jsx +4 -1
  39. package/src/hooks.jsx +55 -55
  40. package/src/misc.jsx +13 -1
  41. package/src/pane.jsx +207 -269
  42. package/webpack.config.js +1 -1
  43. package/docs/static/index 2.html +0 -95
  44. package/root/index 2.html +0 -95
@@ -1418,6 +1418,7 @@ __webpack_require__.d(misc_namespaceObject, {
1418
1418
  isThenable: () => (isThenable),
1419
1419
  isValidElement: () => (isValidElement),
1420
1420
  layout_effects: () => (layout_effects),
1421
+ length_css_attributes_set: () => (length_css_attributes_set),
1421
1422
  mapLocation: () => (mapLocation),
1422
1423
  roots: () => (roots),
1423
1424
  scanFunctionLabels: () => (scanFunctionLabels),
@@ -4628,7 +4629,19 @@ let events_set = new Set([
4628
4629
  "onabort","oncanplay","oncanplaythrough","oncuechange","ondurationchange","onemptied","onended","onerror",
4629
4630
  "onloadeddata","onloadedmetadata","onloadstart","onpause","onplay","onplaying","onprogress","onratechange",
4630
4631
  "onseeked","onseeking","onstalled","onsuspend","ontimeupdate","onvolumechange","onwaiting",
4631
- "ontoggle"
4632
+ "ontoggle",
4633
+
4634
+ "onpointerdown", "onpointerup", "onpointermove", "onpointercancel", "onpointerover", "onpointerout",
4635
+ "onpointerenter", "onpointerleave"
4636
+ ])
4637
+ /** @ignore */
4638
+ let length_css_attributes_set = new Set([
4639
+ "width","height","minWidth","minHeight","maxWidth","maxHeight","top","right","bottom","left","margin",
4640
+ "marginTop","marginRight","marginBottom","marginLeft","padding","paddingTop","paddingRight","paddingBottom",
4641
+ "paddingLeft","borderWidth","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth",
4642
+ "outlineWidth","fontSize","lineHeight","letterSpacing","wordSpacing","textIndent","borderRadius",
4643
+ "borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius",
4644
+ "columnGap","rowGap","gap"
4632
4645
  ])
4633
4646
 
4634
4647
 
@@ -5036,6 +5049,9 @@ class ComponentCore
5036
5049
  this.event_detachers[al] = Lilact.addWrappedEventListener(this.element, al.substring(2), patch[a]);
5037
5050
  }
5038
5051
  else if(al==='style') {
5052
+ for(const x in patch[a]) {
5053
+ if(isFinite(patch[a][x])) patch[a][x]+='px';
5054
+ }
5039
5055
  Object.assign(this.element.style, patch[a]);
5040
5056
  }
5041
5057
  else {
@@ -5052,7 +5068,7 @@ class ComponentCore
5052
5068
  this.element.onsubmit = undefined;
5053
5069
  }
5054
5070
 
5055
- this.element.setAttribute('key', this.props.key);
5071
+ //this.element.setAttribute('key', this.props.key);
5056
5072
 
5057
5073
  this.updateElementClass(patch);
5058
5074
  }
@@ -5785,25 +5801,27 @@ function useState(val)
5785
5801
  * @param {Array<any>} deps - Dependency list.
5786
5802
  * @returns {Function} Memoized callback.
5787
5803
  */
5788
- function useCallback(callback, deps=[{}])
5804
+ function useCallback(callback, deps=undefined)
5789
5805
  {
5806
+ if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
5807
+ throw "callback dependencies must be an array or omitted.";
5808
+ }
5809
+
5790
5810
  const hk = Lilact.useHook();
5791
5811
 
5792
5812
  if( Lilact.isEmpty(hk) ) {
5793
5813
  hk.callback = callback;
5794
- hk.deps = deps;
5795
5814
  }
5796
5815
  else {
5797
- for(let d in deps) {
5798
- if( !Lilact.defaultIsEqual(deps[d],hk.deps[d]) ) {
5799
- hk.callback = callback;
5816
+ if(deps!==undefined && hk?.deps!==undefined && Lilact.shallowEqual(deps, hk.deps)) return hk.callback;
5817
+ }
5800
5818
 
5801
- hk.deps = deps;
5802
- break;
5803
- }
5804
- }
5819
+ if(hk?.cleanup) {
5820
+ hk.cleanup();
5805
5821
  }
5806
5822
 
5823
+ hk.deps = deps;
5824
+
5807
5825
  return hk.callback;
5808
5826
  }
5809
5827
 
@@ -5908,7 +5926,7 @@ function useTransition()
5908
5926
  * @param {any} initialValue - Initial value used if nothing exists in localStorage.
5909
5927
  * @returns {any} Stored state/result.
5910
5928
  */
5911
- function useLocalStorage(key, default_val)
5929
+ function useLocalStorage(key, initialValue)
5912
5930
  {
5913
5931
 
5914
5932
  const hk = Lilact.useHook();
@@ -5921,8 +5939,8 @@ function useLocalStorage(key, default_val)
5921
5939
  }
5922
5940
 
5923
5941
  if(val===undefined) {
5924
- if(typeof(default_val)==='function') default_val = default_val();
5925
- val = default_val;
5942
+ if(typeof(initialValue)==='function') initialValue = initialValue();
5943
+ val = initialValue;
5926
5944
  localStorage[key] = JSON.stringify(val);
5927
5945
  }
5928
5946
 
@@ -5952,12 +5970,12 @@ function useLocalStorage(key, default_val)
5952
5970
  * @param {any} initialValue - Initial ref value.
5953
5971
  * @returns {Object} Ref object with `.current`.
5954
5972
  */
5955
- function useRef(val = null)
5973
+ function useRef(initialValue = null)
5956
5974
  {
5957
5975
  const hk = Lilact.useHook();
5958
5976
 
5959
5977
  if( Lilact.isEmpty(hk) ) {
5960
- hk.current = val;
5978
+ hk.current = initialValue;
5961
5979
  }
5962
5980
 
5963
5981
  return hk;
@@ -5970,25 +5988,25 @@ function useRef(val = null)
5970
5988
  * @param {Array<any>} [deps] - Dependency list.
5971
5989
  * @returns {void}
5972
5990
  */
5973
- function useLayoutEffect(setup, deps=[{}])
5991
+ function useLayoutEffect(effect, deps=undefined)
5974
5992
  {
5975
- if(typeof(deps)!=='object' || deps.constructor.name!=='Array') {
5976
- throw "effect dependencies must be an array or omitted.";
5993
+ if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
5994
+ throw "layout effect dependencies must be an array or omitted.";
5977
5995
  }
5978
5996
 
5979
5997
  const hk = Lilact.useHook();
5980
5998
 
5981
5999
  if( !Lilact.isEmpty(hk) ) {
5982
- if(deps.every((v,i)=> v === hk.deps[i])) return;
5983
- if(hk.cleanup) {
5984
- hk.cleanup();
5985
- }
6000
+ if(deps!==undefined && hk?.deps!==undefined && Lilact.shallowEqual(deps, hk.deps)) return;
6001
+ }
6002
+
6003
+ if(hk?.cleanup) {
6004
+ hk.cleanup();
5986
6005
  }
5987
6006
 
5988
6007
  hk.deps = deps;
5989
- Lilact.layout_effects.add( ()=>{ hk.cleanup = setup(); });
6008
+ Lilact.layout_effects.add( ()=>{ hk.cleanup = effect(); });
5990
6009
  Lilact.current_component[0].component.forceUpdate();
5991
-
5992
6010
  }
5993
6011
 
5994
6012
  /**
@@ -5998,23 +6016,24 @@ function useLayoutEffect(setup, deps=[{}])
5998
6016
  * @param {Array<any>} [deps] - Dependency list.
5999
6017
  * @returns {void}
6000
6018
  */
6001
- function useEffect(setup, deps=[{}])
6019
+ function useEffect(effect, deps=undefined)
6002
6020
  {
6003
- if(typeof(deps)!=='object' || deps.constructor.name!=='Array') {
6021
+ if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
6004
6022
  throw "effect dependencies must be an array or omitted.";
6005
6023
  }
6006
6024
 
6007
6025
  const hk = Lilact.useHook();
6008
6026
 
6009
6027
  if( !Lilact.isEmpty(hk) ) {
6010
- if(deps.every((v,i)=> v === hk.deps[i])) return;
6011
- if(hk.cleanup) {
6012
- hk.cleanup();
6013
- }
6028
+ if(deps!==undefined && hk?.deps!==undefined && Lilact.shallowEqual(deps, hk.deps)) return;
6029
+ }
6030
+
6031
+ if(hk?.cleanup) {
6032
+ hk.cleanup();
6014
6033
  }
6015
6034
 
6016
6035
  hk.deps = deps;
6017
- Lilact.setTimeout( ()=>{ hk.cleanup = setup(); }, 0 );
6036
+ Lilact.setTimeout( ()=>{ hk.cleanup = effect(); }, 0 );
6018
6037
 
6019
6038
  }
6020
6039
 
@@ -6025,24 +6044,21 @@ function useEffect(setup, deps=[{}])
6025
6044
  * @param {Array<any>} deps - Dependency list.
6026
6045
  * @returns {any} Memoized value.
6027
6046
  */
6028
- function useMemo(fn,deps=[])
6047
+ function useMemo(factory,deps=undefined)
6029
6048
  {
6049
+ if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
6050
+ throw "memo dependencies must be an array or omitted.";
6051
+ }
6052
+
6030
6053
  const hk = Lilact.useHook();
6031
6054
 
6032
- if( Lilact.isEmpty(hk) ) {
6033
- hk.deps = deps;
6034
- hk.value = fn();
6035
- }
6036
- else {
6037
- for(let d in deps) {
6038
- if( !Lilact.defaultIsEqual(deps[d],hk.deps[d]) ) {
6039
- hk.deps = deps;
6040
- hk.value = fn(hk.value);
6041
- break;
6042
- }
6043
- }
6055
+ if( !Lilact.isEmpty(hk) ) {
6056
+ if(deps!==undefined && hk?.deps!==undefined && Lilact.shallowEqual(deps, hk.deps)) return hk.value;
6044
6057
  }
6045
6058
 
6059
+ hk.deps = deps;
6060
+ hk.value = factory(hk.value);
6061
+
6046
6062
  return hk.value;
6047
6063
  }
6048
6064
 
@@ -6053,14 +6069,14 @@ function useMemo(fn,deps=[])
6053
6069
  * @param {any} initialState - Initial state for the hook.
6054
6070
  * @returns {any} Hook result
6055
6071
  */
6056
- function useActionState(fn, initial_state)
6072
+ function useActionState(fn, initialState)
6057
6073
  {
6058
6074
  const hk = Lilact.useHook();
6059
6075
  const [is_pending, tran_start_func] = Lilact.useTransition();
6060
6076
 
6061
6077
  if( Lilact.isEmpty(hk) ) {
6062
6078
 
6063
- hk.state = initial_state;
6079
+ hk.state = initialState;
6064
6080
 
6065
6081
  hk.form_action = (sub)=>{
6066
6082
  event.preventDefault();
@@ -6189,18 +6205,18 @@ function forwardRef(render)
6189
6205
  * Dependency list that controls when the exposed value is recalculated.
6190
6206
  * @returns {void}
6191
6207
  */
6192
- function useImperativeHandle(ref, factory, deps)
6208
+ function useImperativeHandle(ref, factory, deps=undefined)
6193
6209
  {
6210
+ if(deps!==undefined && ref?.deps!==undefined && Lilact.shallowEqual(deps, ref.deps)) return;
6211
+
6212
+ ref.deps = deps;
6213
+
6194
6214
  Lilact.setTimeout( ()=>{
6195
- if( !Lilact.defaultIsEqual(deps[d],hk.deps[d]) ) {
6196
-
6197
- hk.deps = deps;
6198
- if(typeof ref.current !== object) {
6199
- ref.current = {};
6200
- }
6201
- Object.assign( ref.current, factory(), 0 );
6202
- }
6203
- });
6215
+ if(typeof ref?.current !== 'object') {
6216
+ ref.current = {};
6217
+ }
6218
+ Object.assign( ref.current, factory(), 0 );
6219
+ }, 0);
6204
6220
  }
6205
6221
 
6206
6222
 
@@ -7716,9 +7732,11 @@ class Suspense extends Component
7716
7732
 
7717
7733
 
7718
7734
 
7719
- function clamp(n, min, max) {
7720
- return Math.max(min, Math.min(max, n));
7721
- }
7735
+
7736
+ const clamp = (n, min, max) => {
7737
+ if (!Number.isFinite(n)) return n;
7738
+ return Math.min(max, Math.max(min, n));
7739
+ };
7722
7740
 
7723
7741
  /**
7724
7742
  * ResizablePane
@@ -7732,248 +7750,190 @@ function clamp(n, min, max) {
7732
7750
  * - Callback when size changes via onSizeChange
7733
7751
  * - Children are rendered in two separate containers (no portals)
7734
7752
  */
7735
- const ResizablePane = forwardRef(function Pane(
7736
- {
7737
- mode = "horizontal", // "horizontal" | "vertical"
7738
- initialPosition, // optional (alias-ish to position)
7739
- position, // controlled position (number)
7740
- defaultPosition = 0.5, // used if position/initialPosition not provided
7741
- min = 0.1, // clamp in "percent of container" units: 0..1
7742
- max = 0.9, // clamp in "percent of container" units: 0..1
7743
- splitterSize = 8, // px thickness of the drag handle
7744
- onSizeChange, // (newPosition: number) => void
7745
- style,
7746
- className,
7747
- leftPaneStyle,
7748
- rightPaneStyle,
7749
- splitterStyle,
7750
- children, // expects two children: [A, B]
7751
- },
7752
- ref
7753
+ const ResizablePane = forwardRef(function ResizablePane(
7754
+ {
7755
+ mode = "horizontal",
7756
+ position, // controlled: number | undefined/null
7757
+ defaultPosition = 0.5,
7758
+ min = 0.1,
7759
+ max = 0.9,
7760
+ splitterSize = 8,
7761
+ onSizeChange,
7762
+ style,
7763
+ className,
7764
+ leftPaneStyle,
7765
+ rightPaneStyle,
7766
+ splitterStyle,
7767
+ children,
7768
+ },
7769
+ ref
7753
7770
  ) {
7754
- const [internalMode, setInternalMode] = useState(mode);
7755
- const [pos, setPos] = useState(() => {
7756
- const start =
7757
- position ?? initialPosition ?? (defaultPosition != null ? defaultPosition : 0.5);
7758
- return clamp(start, min, max);
7759
- });
7771
+ const containerRef = useRef(null);
7772
+ const panes = Children.toArray(children);
7773
+ const leftChild = panes[0] ?? null;
7774
+ const rightChild = panes[1] ?? null;
7760
7775
 
7761
- const containerRef = useRef(null);
7762
- const draggingRef = useRef(false);
7776
+ const isControlled = position != null;
7763
7777
 
7764
- const panes = Children.toArray(children);
7765
- const leftChild = panes[0] ?? null;
7766
- const rightChild = panes[1] ?? null;
7778
+ const [internalMode, setInternalMode] = useState(mode);
7767
7779
 
7768
- const modeResolved = mode != null ? mode : internalMode;
7780
+ const [posUncontrolled, setPosUncontrolled] = useState(() =>
7781
+ clamp(
7782
+ position ?? defaultPosition,
7783
+ min,
7784
+ max
7785
+ )
7786
+ );
7769
7787
 
7770
- // Keep internalMode aligned if mode is provided as a prop
7771
- useEffect(() => {
7772
- if (mode != null) setInternalMode(mode);
7773
- }, [mode]);
7788
+ useEffect(() => {
7789
+ if (mode != null) setInternalMode(mode);
7790
+ }, [mode]);
7774
7791
 
7775
- // Controlled position: update state when prop changes
7776
- useEffect(() => {
7777
- if (position == null) return;
7778
- setPos(clamp(position, min, max));
7779
- }, [position, min, max]);
7780
-
7781
- const setPosition = (newPos) => {
7782
- const next = clamp(newPos, min, max);
7783
- if (position == null) setPos(next); // only update internal state if uncontrolled
7784
- onSizeChange?.(next);
7785
- };
7792
+ // keep internal position clamped if min/max change (uncontrolled only)
7793
+ useLayoutEffect(() => {
7794
+ if (isControlled) return;
7795
+ setPosUncontrolled((p) => clamp(p, min, max));
7796
+ }, [min, max, isControlled]);
7786
7797
 
7787
- const setMode = (nextMode) => {
7788
- const m = nextMode === "vertical" ? "vertical" : "horizontal";
7789
- if (mode == null) setInternalMode(m);
7790
- // If mode is controlled via prop, consumer should re-render with new prop.
7791
- };
7798
+ const posResolved = isControlled ? clamp(position, min, max) : posUncontrolled;
7792
7799
 
7793
- useImperativeHandle(
7794
- ref,
7795
- () => ({
7796
- setPosition,
7797
- setMode,
7798
- getPosition: () => (position == null ? pos : clamp(position, min, max)),
7799
- getMode: () => modeResolved,
7800
- }),
7801
- [pos, position, min, max, modeResolved, onSizeChange, mode]
7802
- );
7800
+ const setPosition = (next) => {
7801
+ const clamped = clamp(next, min, max);
7802
+ if (!isControlled) setPosUncontrolled(clamped);
7803
+ onSizeChange?.(clamped);
7804
+ };
7803
7805
 
7804
- const updateFromClientXorY = (clientX, clientY) => {
7805
- const el = containerRef.current;
7806
- if (!el) return;
7806
+ const draggingRef = useRef(false);
7807
+ const pointerIdRef = useRef(null);
7807
7808
 
7808
- const rect = el.getBoundingClientRect();
7809
- let next;
7809
+ const updateFromClient = (clientX, clientY) => {
7810
+ const el = containerRef.current;
7811
+ if (!el) return;
7810
7812
 
7811
- if (modeResolved === "horizontal") {
7812
- const usable = rect.width;
7813
- if (usable <= 0) return;
7814
- next = (clientX - rect.left) / usable;
7815
- } else {
7816
- const usable = rect.height;
7817
- if (usable <= 0) return;
7818
- next = (clientY - rect.top) / usable;
7819
- }
7820
- setPosition(next);
7821
- };
7813
+ const rect = el.getBoundingClientRect();
7822
7814
 
7823
- const onPointerDown = (e) => {
7824
- e.preventDefault();
7825
- draggingRef.current = true;
7815
+ if (internalMode === "horizontal") {
7816
+ const usable = rect.width;
7817
+ if (!Number.isFinite(usable) || usable <= 0) return; // no jump on init
7818
+ const raw = (clientX - rect.left) / usable;
7819
+ if (!Number.isFinite(raw)) return;
7820
+ setPosition(raw);
7821
+ } else {
7822
+ const usable = rect.height;
7823
+ if (!Number.isFinite(usable) || usable <= 0) return; // no jump on init
7824
+ const raw = (clientY - rect.top) / usable;
7825
+ if (!Number.isFinite(raw)) return;
7826
+ setPosition(raw);
7827
+ }
7828
+ };
7826
7829
 
7827
- // Capture pointer so we still get events outside the handle area.
7828
- try {
7829
- e.currentTarget.setPointerCapture?.(e.pointerId);
7830
- } catch {
7831
- // ignore
7832
- }
7830
+ // stable global listeners: only act while draggingRef.current === true
7831
+ useEffect(() => {
7832
+ const onMove = (e) => {
7833
+ if (!draggingRef.current) return;
7834
+ if (pointerIdRef.current != null && e.pointerId !== pointerIdRef.current) return;
7835
+ updateFromClient(e.clientX, e.clientY);
7836
+ };
7833
7837
 
7834
- updateFromClientXorY(e.clientX, e.clientY);
7835
- };
7838
+ const stop = (e) => {
7839
+ if (!draggingRef.current) return;
7840
+ if (pointerIdRef.current != null && e.pointerId !== pointerIdRef.current) return;
7841
+ draggingRef.current = false;
7842
+ pointerIdRef.current = null;
7843
+ };
7836
7844
 
7837
- const onPointerMove = (e) => {
7838
- if (!draggingRef.current) return;
7839
- updateFromClientXorY(e.clientX, e.clientY);
7840
- };
7845
+ window.addEventListener("pointermove", onMove, { passive: true });
7846
+ window.addEventListener("pointerup", stop, { passive: true });
7847
+ window.addEventListener("pointercancel", stop, { passive: true });
7841
7848
 
7842
- const stopDragging = () => {
7843
- draggingRef.current = false;
7844
- };
7849
+ return () => {
7850
+ window.removeEventListener("pointermove", onMove);
7851
+ window.removeEventListener("pointerup", stop);
7852
+ window.removeEventListener("pointercancel", stop);
7853
+ };
7854
+ }, [internalMode]); // updateFromClient uses internalMode
7845
7855
 
7846
- // Attach global listeners to ensure smooth dragging even if pointer capture fails
7847
- useEffect(() => {
7848
- const handleMove = (e) => {
7849
- if (!draggingRef.current) return;
7850
- updateFromClientXorY(e.clientX, e.clientY);
7851
- };
7852
- const handleUp = () => stopDragging();
7856
+ const onPointerDown = (e) => {
7857
+ if (e.button != null && e.button !== 0) return;
7858
+ e.preventDefault();
7853
7859
 
7854
- window.addEventListener("pointermove", handleMove, { passive: false });
7855
- window.addEventListener("pointerup", handleUp, { passive: true });
7856
- window.addEventListener("pointercancel", handleUp, { passive: true });
7860
+ draggingRef.current = true;
7861
+ pointerIdRef.current = e.pointerId;
7857
7862
 
7858
- return () => {
7859
- window.removeEventListener("pointermove", handleMove);
7860
- window.removeEventListener("pointerup", handleUp);
7861
- window.removeEventListener("pointercancel", handleUp);
7862
- };
7863
- }, [modeResolved, min, max, position, onSizeChange]);
7863
+ try {
7864
+ e.currentTarget.setPointerCapture?.(e.pointerId);
7865
+ } catch {}
7866
+
7867
+ updateFromClient(e.clientX, e.clientY); // first update only if rect is sane
7868
+ };
7864
7869
 
7865
- const posResolved = position == null ? pos : clamp(position, min, max);
7870
+ const onKeyDown = (e) => {
7871
+ const step = 0.02;
7872
+ let delta = 0;
7866
7873
 
7867
- const sizes = useMemo(() => {
7868
- if (modeResolved === "horizontal") {
7869
- // left width = pos, splitter width = splitterSize, right flexes
7870
- // We set left/right as percentages and keep splitter fixed in px.
7871
- return {
7872
- left: `${posResolved * 100}%`,
7873
- right: `calc(${100 - posResolved * 100}% - ${splitterSize}px)`,
7874
- };
7875
- }
7876
- return {
7877
- left: `${posResolved * 100}%`,
7878
- right: `calc(${100 - posResolved * 100}% - ${splitterSize}px)`,
7879
- };
7880
- }, [modeResolved, posResolved, splitterSize]);
7881
-
7882
- // Improve keyboard accessibility (arrow keys when handle is focused)
7883
- const onSplitterKeyDown = (e) => {
7884
- const step = 0.02;
7885
- let delta = 0;
7886
- if (modeResolved === "horizontal") {
7887
- if (e.key === "ArrowLeft") delta = -step;
7888
- if (e.key === "ArrowRight") delta = step;
7889
- } else {
7890
- if (e.key === "ArrowUp") delta = -step;
7891
- if (e.key === "ArrowDown") delta = step;
7892
- }
7893
- if (delta !== 0) {
7894
- e.preventDefault();
7895
- setPosition(posResolved + delta);
7896
- }
7897
- };
7874
+ if (internalMode === "horizontal") {
7875
+ if (e.key === "ArrowLeft") delta = -step;
7876
+ if (e.key === "ArrowRight") delta = step;
7877
+ } else {
7878
+ if (e.key === "ArrowUp") delta = -step;
7879
+ if (e.key === "ArrowDown") delta = step;
7880
+ }
7898
7881
 
7899
- // Ensure position clamps correctly if min/max change
7900
- useLayoutEffect(() => {
7901
- setPos((p) => clamp(p, min, max));
7902
- }, [min, max]);
7903
-
7904
- const rootStyle = {
7905
- display: "flex",
7906
- width: "100%",
7907
- height: "100%",
7908
- overflow: "hidden",
7909
- touchAction: "none",
7910
- ...(style || {}),
7911
- flexDirection: modeResolved === "horizontal" ? "row" : "column",
7912
- };
7882
+ if (delta !== 0) {
7883
+ e.preventDefault();
7884
+ setPosition(posResolved + delta);
7885
+ }
7886
+ };
7913
7887
 
7914
- const leftPaneComputed =
7915
- modeResolved === "horizontal"
7916
- ? {
7917
- width: sizes.left,
7918
- flex: `0 0 ${sizes.left}`,
7919
- overflow: "auto",
7920
- ...(leftPaneStyle || {}),
7921
- }
7922
- : {
7923
- height: sizes.left,
7924
- flex: `0 0 ${sizes.left}`,
7925
- overflow: "auto",
7926
- ...(leftPaneStyle || {}),
7927
- };
7928
-
7929
- const rightPaneComputed =
7930
- modeResolved === "horizontal"
7931
- ? {
7932
- width: `calc(${100 - posResolved * 100}% - ${splitterSize}px)`,
7933
- flex: `1 1 auto`,
7934
- overflow: "auto",
7935
- ...(rightPaneStyle || {}),
7936
- }
7937
- : {
7938
- height: `calc(${100 - posResolved * 100}% - ${splitterSize}px)`,
7939
- flex: `1 1 auto`,
7940
- overflow: "auto",
7941
- ...(rightPaneStyle || {}),
7942
- };
7943
-
7944
- const splitterComputed =
7945
- modeResolved === "horizontal"
7946
- ? {
7947
- width: `${splitterSize}px`,
7948
- flex: `0 0 ${splitterSize}px`,
7949
- cursor: "col-resize",
7950
- background: "transparent",
7951
- ...(splitterStyle || {}),
7952
- }
7953
- : {
7954
- height: `${splitterSize}px`,
7955
- flex: `0 0 ${splitterSize}px`,
7956
- cursor: "row-resize",
7957
- background: "transparent",
7958
- ...(splitterStyle || {}),
7959
- };
7960
-
7961
- const dividerVisualStyle =
7962
- modeResolved === "horizontal"
7963
- ? {
7964
- height: "100%",
7965
- width: "100%",
7966
- background: "rgba(0,0,0,0.08)",
7967
- }
7968
- : {
7969
- width: "100%",
7970
- height: "100%",
7971
- background: "rgba(0,0,0,0.08)",
7972
- };
7888
+ const sizes = useMemo(() => {
7889
+ const leftPct = `${posResolved * 100}%`;
7890
+ const rightCalc = `calc(${100 - posResolved * 100}% - ${splitterSize}px)`;
7891
+ return { leftPct, rightCalc };
7892
+ }, [posResolved, splitterSize]);
7893
+
7894
+ const rootStyle = {
7895
+ display: "flex",
7896
+ width: "100%",
7897
+ height: "100%",
7898
+ overflow: "hidden",
7899
+ touchAction: "none",
7900
+ ...(style || {}),
7901
+ flexDirection: internalMode === "horizontal" ? "row" : "column",
7902
+ };
7973
7903
 
7974
- return (
7975
- Lilact.createComponent( "div", { "ref": containerRef, "className": className, "style": rootStyle, "onPointerMove": onPointerMove }, Lilact.createComponent( "div", { "style": leftPaneComputed }, leftChild ), Lilact.createComponent( "div", { "role": "separator", "aria-orientation": modeResolved === "horizontal" ? "vertical" : "horizontal", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": posResolved, "tabIndex": 0, "onPointerDown": onPointerDown, "onPointerUp": stopDragging, "onPointerCancel": stopDragging, "onKeyDown": onSplitterKeyDown, "style": splitterComputed }, Lilact.createComponent( "div", { "style": dividerVisualStyle } ) ), Lilact.createComponent( "div", { "style": rightPaneComputed }, rightChild ) )
7976
- );
7904
+ const leftPaneComputed =
7905
+ internalMode === "horizontal"
7906
+ ? { width: sizes.leftPct, flex: `0 0 ${sizes.leftPct}`, overflow: "auto", ...(leftPaneStyle || {}) }
7907
+ : { height: sizes.leftPct, flex: `0 0 ${sizes.leftPct}`, overflow: "auto", ...(leftPaneStyle || {}) };
7908
+
7909
+ const rightPaneComputed =
7910
+ internalMode === "horizontal"
7911
+ ? { width: sizes.rightCalc, flex: "1 1 auto", overflow: "auto", ...(rightPaneStyle || {}) }
7912
+ : { height: sizes.rightCalc, flex: "1 1 auto", overflow: "auto", ...(rightPaneStyle || {}) };
7913
+
7914
+ const splitterComputed =
7915
+ internalMode === "horizontal"
7916
+ ? { width: `${splitterSize}px`, height: '100%', flex: `0 0 ${splitterSize}px`, background: "rgba(0,0,0,0.08)", cursor: "col-resize", ...(splitterStyle || {}) }
7917
+ : { height: `${splitterSize}px`, width: '100%', flex: `0 0 ${splitterSize}px`, background: "rgba(0,0,0,0.08)", cursor: "row-resize", ...(splitterStyle || {}) };
7918
+
7919
+ const dividerVisualStyle =
7920
+ internalMode === "horizontal"
7921
+ ? { height: "100%", width: "100%" }
7922
+ : { width: "100%", height: "100%" };
7923
+
7924
+ useImperativeHandle(ref, () => ({
7925
+ setPosition,
7926
+ setMode: (nextMode) => setInternalMode(nextMode === "vertical" ? "vertical" : "horizontal"),
7927
+ getPosition: () => posResolved,
7928
+ getMode: () => internalMode,
7929
+ }));
7930
+
7931
+ return (
7932
+ Lilact.createComponent( "div", { "ref": containerRef, "className": className, "style": rootStyle }, Lilact.createComponent( "div", { "style": leftPaneComputed }, leftChild ), Lilact.createComponent( "div", { "role": "separator", "aria-orientation": internalMode === "horizontal" ? "vertical" : "horizontal", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": posResolved, "tabIndex": 0, "onPointerDown": onPointerDown, "onPointerCancel": () => {
7933
+ draggingRef.current = false;
7934
+ pointerIdRef.current = null;
7935
+ }, "onKeyDown": onKeyDown, "style": splitterComputed }, Lilact.createComponent( "div", { "style": dividerVisualStyle } ) ), Lilact.createComponent( "div", { "style": rightPaneComputed }, rightChild ) )
7936
+ );
7977
7937
  });
7978
7938
 
7979
7939