diff --git a/.changeset/perfect-eagles-add.md b/.changeset/perfect-eagles-add.md
new file mode 100644
index 0000000..76ec7df
--- /dev/null
+++ b/.changeset/perfect-eagles-add.md
@@ -0,0 +1,7 @@
+---
+'@reactlit/radix': patch
+'@reactlit/core': patch
+'@reactlit/vanilla': patch
+---
+
+fix to tunnel ordering
diff --git a/apps/reactlit-examples/src/pages/hello-world/index.tsx b/apps/reactlit-examples/src/pages/hello-world/index.tsx
index d148c46..2fa51d1 100644
--- a/apps/reactlit-examples/src/pages/hello-world/index.tsx
+++ b/apps/reactlit-examples/src/pages/hello-world/index.tsx
@@ -1,5 +1,5 @@
import { Reactlit, useReactlitState } from '@reactlit/core';
-import { Inputs } from '@reactlit/radix';
+import { Inputs, Label } from '@reactlit/radix';
export default function HelloWorld() {
const [appState, setAppState] = useReactlitState({
@@ -11,8 +11,8 @@ export default function HelloWorld() {
display(
Hello World
);
const name = view(
'name',
+ Label('Name'),
Inputs.Text({
- label: 'Name',
placeholder: 'Enter your name',
})
);
diff --git a/apps/reactlit-examples/src/pages/radix-inputs/index.tsx b/apps/reactlit-examples/src/pages/radix-inputs/index.tsx
index 7a37cbc..2778412 100644
--- a/apps/reactlit-examples/src/pages/radix-inputs/index.tsx
+++ b/apps/reactlit-examples/src/pages/radix-inputs/index.tsx
@@ -1,4 +1,4 @@
-import { useDebug } from '@/components/debug-toggle';
+import { Debug, useDebug } from '@/components/debug-toggle';
import {
Badge,
ChevronDownIcon,
@@ -60,14 +60,16 @@ const ResultsWrapper: Wrapper = ({ children }) => {
const [open, setOpen] = useState(true);
return (
setOpen(!open)}
>
{open ? : }
Results
-
{children}
+
+ {children}
+
);
};
@@ -84,6 +86,7 @@ export default function RadixInputs() {
color: 'red',
slider: 0,
rangeSlider: [20, 80],
+ enableLetter: true,
});
const debug = useDebug();
return (
@@ -92,6 +95,9 @@ export default function RadixInputs() {
{async ({ display, view }) => {
display(Inputs test
);
const [results] = view('results', ResultsWrapper, LayoutView(1));
+ const displayResult = (label: string, value: React.ReactNode) => {
+ results.display(Debug, DisplayLabel(label), value);
+ };
const name = view(
'name',
Label('Name'),
@@ -99,7 +105,7 @@ export default function RadixInputs() {
placeholder: 'Enter your name',
})
);
- results.display(DisplayLabel('Name'), name);
+ displayResult('Name', name);
const bio = view(
'bio',
Label('Bio'),
@@ -107,29 +113,35 @@ export default function RadixInputs() {
placeholder: 'Enter your bio',
})
);
- results.display(DisplayLabel('Bio'), bio);
+ displayResult('Bio', bio);
const number = view(
'number',
Label('Pick any numbers'),
Inputs.Check({ one: '1', two: '2', three: '3' })
);
- results.display(DisplayLabel('Numbers'), number);
- const letter = view(
- 'letter',
- Label('Pick one Letter'),
- Inputs.Radio(['A', 'B', 'C'])
- );
- results.display(DisplayLabel('Letter'), letter);
+ displayResult('Numbers', number);
+ if (
+ view(
+ 'enableLetter',
+ Label('Letter Selection'),
+ ,
+ Inputs.Switch()
+ )
+ ) {
+ const letter = view(
+ 'letter',
+ Label('Pick one Letter'),
+ Inputs.Radio(['A', 'B', 'C'])
+ );
+ displayResult('Letter', letter);
+ }
const color = view(
'color',
Label('Pick a color'),
,
Inputs.Select(['red', 'blue', 'green'] as const)
);
- results.display(
- DisplayLabel('Color'),
- {color}
- );
+ displayResult('Color', {color});
const slider = view(
'slider',
Label('Slider'),
@@ -138,7 +150,7 @@ export default function RadixInputs() {
max: 100,
})
);
- results.display(DisplayLabel('Slider'), slider);
+ displayResult('Slider', slider);
const rangeSlider = view(
'rangeSlider',
Label('Range Slider'),
@@ -147,10 +159,7 @@ export default function RadixInputs() {
max: 100,
})
);
- results.display(
- DisplayLabel('Range Slider'),
- rangeSlider.join(' - ')
- );
+ displayResult('Range Slider', rangeSlider.join(' - '));
const countries = await fetchCountries();
display(Select a country
);
const filteredCountries = view(
@@ -168,8 +177,8 @@ export default function RadixInputs() {
className: 'h-[300px]',
})
);
- results.display(
- DisplayLabel('Country'),
+ displayResult(
+ 'Country',
<>
{selectedCountry?.code ? (
(
ctx: Pick, 'display' | 'view'>,
t: ReturnType
): LayoutSlot {
- const TunnelWrapper: Wrapper = ({ stateKey, children }) => {
- return {children};
+ const TunnelWrapper: Wrapper = ({ stateKey, position, children }) => {
+ return (
+
+ {children}
+
+ );
};
return {
display(...args) {
diff --git a/libs/core/src/reactlit.tsx b/libs/core/src/reactlit.tsx
index b09209e..08c0ff1 100644
--- a/libs/core/src/reactlit.tsx
+++ b/libs/core/src/reactlit.tsx
@@ -14,6 +14,8 @@ import { useReactlitSet } from './builtins/set';
import { ReactlitProps, StateBase } from './builtins/types';
import { useReactlitView } from './builtins/view';
import { useReactlitState } from './hooks/use-reactlit-state';
+import { useIsomorphicLayoutEffect } from './utils/use-isomorphic-layout-effect';
+import { uniqueBy } from './utils/unique-by';
const defaultRenderError = ({ error }) => (
@@ -55,7 +57,7 @@ export function Reactlit
({
const renderLock = useRef(false);
const renderAfter = useRef(false);
- useEffect(() => {
+ useIsomorphicLayoutEffect(() => {
async function runScript() {
setRendering(true);
if (renderLock.current) {
@@ -103,7 +105,7 @@ export function Reactlit({
return (
<>
- {renderState.elements.map(([key, node]) => (
+ {uniqueBy(renderState.elements, '0').map(([key, node]) => (
{node}
))}
{renderLoading?.(rendering) ?? <>>}
diff --git a/libs/core/src/utils/tunnel.tsx b/libs/core/src/utils/tunnel.tsx
index 3be4fda..8c1a603 100644
--- a/libs/core/src/utils/tunnel.tsx
+++ b/libs/core/src/utils/tunnel.tsx
@@ -1,26 +1,31 @@
import React, { Fragment } from 'react';
import { create, StoreApi } from 'zustand';
import { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect';
+import { uniqueBy } from './unique-by';
// modified from tunnel-rat
-type Props = { childKey: string; children: React.ReactNode };
+type Props = { childKey: string; order: number; children: React.ReactNode };
type State = {
- current: Array<{ childKey: string; node: React.ReactNode }>;
+ current: Array;
version: number;
set: StoreApi['setState'];
};
+function sortByOrder(array: Props[]) {
+ return array.sort((a, b) => a.order - b.order);
+}
+
export default function tunnel() {
const useStore = create((set) => ({
- current: new Array<{ childKey: string; node: React.ReactNode }>(),
+ current: new Array(),
version: 0,
set,
}));
return {
- In: ({ childKey, children }: Props) => {
+ In: ({ childKey, order, children }: Props) => {
const set = useStore((state) => state.set);
const version = useStore((state) => state.version);
@@ -40,22 +45,25 @@ export default function tunnel() {
set(({ current }) => {
const existing = current.findIndex((c) => c.childKey === childKey);
return {
- current:
+ current: sortByOrder(
existing !== -1
? [
...current.slice(0, existing),
- { childKey, node: children },
+ { childKey, order, children },
...current.slice(existing + 1),
]
- : [...current, { childKey, node: children }],
+ : [...current, { childKey, order, children }]
+ ),
};
});
// remove the cleanup logic so that nodes stay in position, the key logic keeps things from getting too messy
- // return () =>
- // set(({ current }) => ({
- // current: current.filter((c) => c.node !== children),
- // }));
+ return () =>
+ set(({ current }) => {
+ return {
+ current: current.filter((c) => c.childKey !== childKey),
+ };
+ });
}, [children, version]);
return null;
@@ -65,8 +73,8 @@ export default function tunnel() {
const current = useStore((state) => state.current);
return (
<>
- {current.map((c) => (
- {c.node}
+ {uniqueBy(current, 'childKey').map((c) => (
+ {c.children}
))}
>
);
diff --git a/libs/core/src/utils/unique-by.ts b/libs/core/src/utils/unique-by.ts
new file mode 100644
index 0000000..f3ce6e2
--- /dev/null
+++ b/libs/core/src/utils/unique-by.ts
@@ -0,0 +1,5 @@
+export function uniqueBy(array: T[], key: keyof T) {
+ return array.filter(
+ (item, index, self) => index === self.findIndex((t) => t[key] === item[key])
+ );
+}
diff --git a/libs/radix/src/inputs/search.input.tsx b/libs/radix/src/inputs/search.input.tsx
index 3dd4d1c..dead533 100644
--- a/libs/radix/src/inputs/search.input.tsx
+++ b/libs/radix/src/inputs/search.input.tsx
@@ -37,7 +37,6 @@ export function SearchInput(
(viewProps) => (
& {
- label?: LabelType;
-};
+>;
export const SwitchInputComponent = ({
value,
stateKey,
setValue,
- label,
display,
view,
...props
diff --git a/libs/radix/src/inputs/text.input.tsx b/libs/radix/src/inputs/text.input.tsx
index f431a68..1bacdb1 100644
--- a/libs/radix/src/inputs/text.input.tsx
+++ b/libs/radix/src/inputs/text.input.tsx
@@ -5,7 +5,6 @@ import { useDebouncedCallback } from 'use-debounce';
import { LabelType } from '../label';
export type TextInputProps = Omit & {
- label?: LabelType;
children?:
| React.ReactNode
| ((props: ViewComponentProps) => React.ReactNode);
@@ -17,7 +16,6 @@ export const TextInputComponent = ({
stateKey,
setValue,
onChange,
- label,
debounceDelay = 200,
children,
display,