agentsmith
agentsmith
SSolidJS
Created by agentsmith on 10/31/2024 in #support
Reactivity with shadcn-solid textfield
I created my own NumberInput using https://shadcn-solid.com/docs/components/textfield. I see they have a number field, but I wanted the more typical html number input. My implementation has 4 number inputs that are clamped based on min/max values. I'm testing by manually typing -1 in the field. Technically a 1 and then I'm adding a - to it since it won't input otherwise. The clamp works for 2 of the inputs, but fails for the other 2. It seems to be losing the reactivity somehow. I've tried adding createMemo around the value to ensure the reactivity is present although I don't believe that shouldn't be necessary since I'm passing the accessor. I might see about creating a minimal example for this, but for now here's the code for the NumberInput and the implementation using is.
import { createMemo } from 'solid-js'
import {
TextField,
TextFieldLabel,
TextFieldDescription,
TextFieldRoot,
} from '@/components/ui/textfield'

import type { Component, Accessor } from 'solid-js'
import type { JSX } from 'solid-js/jsx-runtime'

type NumberValue = number | Accessor<number>
type NumberSetter = ((v: number) => void) | ((prev: number) => number)

interface NumberInputProps {
id: string
label: JSX.Element
info?: JSX.Element
class?: string
min?: number
max?: number
value?: NumberValue
onInput?: NumberSetter
}

export const NumberInput: Component<NumberInputProps> = (props) => {
// const getValue = (): string => {
// console.log('getValue:', props.value)
// if (props.value === undefined) return ''
// return typeof props.value === 'function' ? props.value().toString() : props.value.toString()
// }
const value = createMemo(() => {
console.log('getValue:', typeof props.value === 'function' ? props.value() : props.value)
if (props.value === undefined) return ''
return typeof props.value === 'function' ? props.value().toString() : props.value.toString()
})

const clampValue = (value: number): number => {
let clampedValue = value

if (props.min !== undefined) {
clampedValue = Math.max(props.min, clampedValue)
}

if (props.max !== undefined) {
clampedValue = Math.min(props.max, clampedValue)
}

return clampedValue
}

const handleInput = (e: Event) => {
const target = e.target as HTMLInputElement
const newValue = clampValue(Number(target.value))
console.log('setValue:', target.value, newValue)

props.onInput?.(newValue)
}

return (
<TextFieldRoot
class={props.class ?? 'w-24'}
// defaultValue={getValue()}
>
<TextFieldLabel for={props.id}>{props.label}</TextFieldLabel>
<TextField
id={props.id}
type="number"
min={props.min}
max={props.max}
value={value()}
onInput={handleInput}
/>
<TextFieldDescription>{props.info}</TextFieldDescription>
</TextFieldRoot>
)
}

export default NumberInput
import { createMemo } from 'solid-js'
import {
TextField,
TextFieldLabel,
TextFieldDescription,
TextFieldRoot,
} from '@/components/ui/textfield'

import type { Component, Accessor } from 'solid-js'
import type { JSX } from 'solid-js/jsx-runtime'

type NumberValue = number | Accessor<number>
type NumberSetter = ((v: number) => void) | ((prev: number) => number)

interface NumberInputProps {
id: string
label: JSX.Element
info?: JSX.Element
class?: string
min?: number
max?: number
value?: NumberValue
onInput?: NumberSetter
}

export const NumberInput: Component<NumberInputProps> = (props) => {
// const getValue = (): string => {
// console.log('getValue:', props.value)
// if (props.value === undefined) return ''
// return typeof props.value === 'function' ? props.value().toString() : props.value.toString()
// }
const value = createMemo(() => {
console.log('getValue:', typeof props.value === 'function' ? props.value() : props.value)
if (props.value === undefined) return ''
return typeof props.value === 'function' ? props.value().toString() : props.value.toString()
})

const clampValue = (value: number): number => {
let clampedValue = value

if (props.min !== undefined) {
clampedValue = Math.max(props.min, clampedValue)
}

if (props.max !== undefined) {
clampedValue = Math.min(props.max, clampedValue)
}

return clampedValue
}

const handleInput = (e: Event) => {
const target = e.target as HTMLInputElement
const newValue = clampValue(Number(target.value))
console.log('setValue:', target.value, newValue)

props.onInput?.(newValue)
}

return (
<TextFieldRoot
class={props.class ?? 'w-24'}
// defaultValue={getValue()}
>
<TextFieldLabel for={props.id}>{props.label}</TextFieldLabel>
<TextField
id={props.id}
type="number"
min={props.min}
max={props.max}
value={value()}
onInput={handleInput}
/>
<TextFieldDescription>{props.info}</TextFieldDescription>
</TextFieldRoot>
)
}

export default NumberInput
14 replies
SSolidJS
Created by agentsmith on 10/11/2024 in #support
Fundamental reactivity
I must be missing something fundamental about how to implement that reactivity in SolidJS. I have a Card component (multiple for testing). That component includes some inputs with data that will be passed to child component (chart) which should trigger an update for that child component. Parent Card(s) Component
import { createSignal, createEffect } from 'solid-js'
import { Card, CardHeader, CardContent, CardTitle } from '@/components/ui/card'
import { TextField, TextFieldLabel, TextFieldRoot } from '@/components/ui/textfield'
import ProbabilityConesChart, { ConeType } from '@/components/charts/ProbabilityCones'

import type { Component } from 'solid-js'
import type { ProcessedData } from '@/libs/stats'

interface CardProps {
data: ProcessedData | null
}

export const ProbabilityConesCard: Component<CardProps> = (props) => {
const [coneSize, setConeSize] = createSignal(30)

// createEffect(() => {
// console.log('here', coneSize())
// })

return (
<div class="grid grid-cols-1 2xl:grid-cols-2 gap-6 mt-6">
<Card>
<CardHeader class="flex flex-row">
<CardTitle>Probability Cones</CardTitle>
<TextFieldRoot class="mt-0">
<TextFieldLabel for="coneSize">Cone Size</TextFieldLabel>
<TextField
id="coneSize"
class="mt-2"
type="number"
min={1}
value={coneSize()}
// onInput={(e) => setConeSize(Number((e.target as HTMLInputElement).value))}
onInput={(e) => {
console.log('here', coneSize())
setConeSize(Number((e.target as HTMLInputElement).value))
}}
/>
</TextFieldRoot>
</CardHeader>
<CardContent>
<ProbabilityConesChart
data={props.data}
coneLength={coneSize()}
/>
</CardContent>
</Card>

<Card>
<CardHeader>
<CardTitle>Probability Cones</CardTitle>
</CardHeader>
<CardContent>
<ProbabilityConesChart
data={props.data}
coneType={ConeType.Linear}
/>
</CardContent>
</Card>
</div>
)
}

export default ProbabilityConesCard
import { createSignal, createEffect } from 'solid-js'
import { Card, CardHeader, CardContent, CardTitle } from '@/components/ui/card'
import { TextField, TextFieldLabel, TextFieldRoot } from '@/components/ui/textfield'
import ProbabilityConesChart, { ConeType } from '@/components/charts/ProbabilityCones'

import type { Component } from 'solid-js'
import type { ProcessedData } from '@/libs/stats'

interface CardProps {
data: ProcessedData | null
}

export const ProbabilityConesCard: Component<CardProps> = (props) => {
const [coneSize, setConeSize] = createSignal(30)

// createEffect(() => {
// console.log('here', coneSize())
// })

return (
<div class="grid grid-cols-1 2xl:grid-cols-2 gap-6 mt-6">
<Card>
<CardHeader class="flex flex-row">
<CardTitle>Probability Cones</CardTitle>
<TextFieldRoot class="mt-0">
<TextFieldLabel for="coneSize">Cone Size</TextFieldLabel>
<TextField
id="coneSize"
class="mt-2"
type="number"
min={1}
value={coneSize()}
// onInput={(e) => setConeSize(Number((e.target as HTMLInputElement).value))}
onInput={(e) => {
console.log('here', coneSize())
setConeSize(Number((e.target as HTMLInputElement).value))
}}
/>
</TextFieldRoot>
</CardHeader>
<CardContent>
<ProbabilityConesChart
data={props.data}
coneLength={coneSize()}
/>
</CardContent>
</Card>

<Card>
<CardHeader>
<CardTitle>Probability Cones</CardTitle>
</CardHeader>
<CardContent>
<ProbabilityConesChart
data={props.data}
coneType={ConeType.Linear}
/>
</CardContent>
</Card>
</div>
)
}

export default ProbabilityConesCard
8 replies
SSolidJS
Created by agentsmith on 10/4/2024 in #support
solid-plotly.js a new wrapper for Plotly.js
I could use some more experienced eyes to check the SolidJS implementation details. Eventually I'd like to get this into the official plotly.js distributions. https://github.com/ralphsmith80/solid-plotly.js/tree/main I've posted on there support forum about that as well. https://community.plotly.com/t/solidjs-version-of-plotly-could-use-some-eyeballs/87761
I want to use Plotly with SolidJS. The closest match would be React, but they’re fundamentally different. I used the React project to build a similar wrapper using SolidJS. ralphsmith80/solid-plotly.js: A plotly.js SolidJS component from Plotly (github.com) It’s a monorepo using pnpm. The solid-plotly.js packages is under packages and the demo app is under apps. I’d like to see about getting this included into the available plotly packages. I could use some eyes on the project and there’s still some work around testing and documentation that needs to be done. In particular I’m struggling to get the same tests working that are in the react repository. The differences revolve around the expectPlotlyAPICall test function and I’m sure it’s related to the fact that I wrote the solidjs version using TS which I’m not very good at yet. For docs the README pages need to be updated.
105 replies
SSolidJS
Created by agentsmith on 8/27/2024 in #support
Aceternity UI components
No description
59 replies