Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a458b01
working on cleaning up and simplifying lists
chrisdrackett Jan 16, 2026
d6b28a4
remove yarn.lock from paradigm
chrisdrackett Jan 16, 2026
6091ee3
Revert "remove yarn.lock from paradigm"
chrisdrackett Jan 16, 2026
c0e96f4
remove console.log
chrisdrackett Jan 16, 2026
d19ae53
update paradigm to not have a lockfile to support monorepos
chrisdrackett Jan 16, 2026
8d76bf9
allow local PRs without lockfiles to build
chrisdrackett Jan 16, 2026
07d43e7
ignore yarn.lock
chrisdrackett Jan 16, 2026
34c0188
more list cleanup
chrisdrackett Jan 16, 2026
9bcf061
add quick spring
chrisdrackett Jan 17, 2026
929a1cf
link chromatic
chrisdrackett Jan 28, 2026
b1fdc83
pulling in official window splitter fix
chrisdrackett Feb 3, 2026
14f2b44
update icons and other components to all use the same color value
chrisdrackett Feb 10, 2026
01d363c
nums to dict
chrisdrackett Feb 10, 2026
3c4ad27
adding theme values
chrisdrackett Feb 10, 2026
9698ac0
more work on icon types
chrisdrackett Feb 11, 2026
bd9dd84
starting work on settings lists
chrisdrackett Feb 11, 2026
1fdcc97
update to tamagui 2.0
chrisdrackett Feb 11, 2026
a292f21
reconcile icon sizing types
chrisdrackett Feb 12, 2026
48b27c9
fix default positon
chrisdrackett Feb 12, 2026
9963922
remove unused setting
chrisdrackett Feb 12, 2026
1b4518c
type and tamagui clean up
chrisdrackett Feb 12, 2026
49744c4
more work on info settings list item
chrisdrackett Feb 12, 2026
28935f3
info settings item
chrisdrackett Mar 3, 2026
f4e6041
add switch
chrisdrackett Mar 3, 2026
4dad86a
update theme support
chrisdrackett Mar 4, 2026
422ea06
pull pressable out into its own component
chrisdrackett Mar 11, 2026
b521bfa
initial slider
chrisdrackett Mar 11, 2026
d3b0415
finish first pass on slider
chrisdrackett Mar 16, 2026
4121e80
first pass on select settings item
chrisdrackett Mar 16, 2026
9c8c3fa
add system as an option
chrisdrackett Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/actions/setup-node/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ runs:
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: yarn

- name: Install dependencies
run: yarn install --immutable
shell: bash
run: yarn install --no-immutable
shell: bash
env:
YARN_ENABLE_HARDENED_MODE: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && '1' || '0' }}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ storybook-static
.tamagui

# env
.env
.env

# for monorepo use
yarn.lock
1 change: 0 additions & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export default defineMain({
tamaguiPlugin({
config: "./src/config/tamagui.config.ts",
components: ["tamagui"],
optimize: true,
}),
],
build: {
Expand Down
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
".tamagui": true,
".yarn": true
},
"typescript.preferences.importModuleSpecifier": "relative",

"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"package.json": "package-lock.json, yarn.lock, .yarnrc.yml, cspell.config.yaml, biome.json, LICENSE, .gitignore",
Expand Down
5 changes: 5 additions & 0 deletions chromatic.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"onlyChanged": true,
"projectId": "Project:62fea75bb5d432cf221355c3",
"zip": true
Comment on lines +2 to +4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Biome] reported by reviewdog 🐶

Suggested change
"onlyChanged": true,
"projectId": "Project:62fea75bb5d432cf221355c3",
"zip": true
"onlyChanged": true,
"projectId": "Project:62fea75bb5d432cf221355c3",
"zip": true

}
1 change: 1 addition & 0 deletions cspell.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ words:
- culori
- mongolyy
- nderscore
- nums
- unplugin
ignoreWords: []
import: []
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"scripts": {
"start": "storybook dev -p 6006 --no-open --quiet",
"storybook:build": "storybook build",
"storybook:test": "vitest --project=storybook",
"sync": "tsx scripts/syncFigma.ts",
"lint": "biome check .",
"format": "biome check --write .",
Expand All @@ -20,8 +21,8 @@
},
"dependencies": {
"@fontsource/nunito-sans": "^5.2.7",
"@tamagui/config": "1.137.3",
"@window-splitter/react": "^1.1.2",
"@tamagui/config": "2.0.0-rc.11",
"@window-splitter/react": "^1.1.3",
"browser-info": "^1.3.0",
"culori": "^4.0.2",
"motion": "^12.23.26",
Expand All @@ -31,18 +32,18 @@
"react-native-device-info": "^15.0.1",
"react-native-web": "^0.21.2",
"rtl-detect": "^1.1.2",
"tamagui": "1.137.3"
"tamagui": "2.0.0-rc.11"
},
"devDependencies": {
"@biomejs/biome": "2.3.11",
"@chromatic-com/storybook": "^4.1.2",
"@chromatic-com/storybook": "^5.0.0",
"@storybook/addon-a11y": "^10.0.7",
"@storybook/addon-docs": "^10.0.7",
"@storybook/addon-vitest": "^10.0.7",
"@storybook/react-vite": "^10.0.7",
"@svgr/core": "^8.1.0",
"@svgr/plugin-jsx": "^8.1.0",
"@tamagui/vite-plugin": "1.137.3",
"@tamagui/vite-plugin": "2.0.0-rc.11",
"@types/culori": "^4",
"@types/node": "^22.10.2",
"@types/pluralize": "^0.0.33",
Expand All @@ -52,7 +53,7 @@
"@types/rtl-detect": "^1",
"@vitejs/plugin-react": "^5.0.4",
"@vitest/browser-playwright": "^4.0.8",
"@vitest/coverage-v8": "^4.0.8",
"@vitest/coverage-v8": "^4.0.17",
"dotenv": "^17.2.3",
"jsdom": "^27.0.0",
"patch-package": "^8.0.1",
Expand Down
Empty file.
15 changes: 0 additions & 15 deletions patches/@window-splitter+state+1.1.2.patch

This file was deleted.

6 changes: 1 addition & 5 deletions scripts/syncFigma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,7 @@ async function generateTypeScriptFile(
.map(({ name }) => `import ${name} from "./${name}"`)
.join("\n")

const exports = sortedIcons
.map(({ name }) => `\t${name}: ${name} as WebIconComponentType,`)
.join("\n")
const exports = sortedIcons.map(({ name }) => `\t${name},`).join("\n")

const attachments = sortedIcons
.map(({ name }) => `Icon.${name} = rawIcons.${name}`)
Expand All @@ -221,8 +219,6 @@ import { ComponentError } from "../../ComponentError"
// Generated Icons:
${imports}

import type { WebIconComponentType } from "../types"

export const rawIcons = {
${exports}
} as const
Expand Down
31 changes: 31 additions & 0 deletions src/components/AfterText/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react"

import { Text } from "../Text"

/**
* Text to show after an element. Used mostly for lists.
*/
type AfterTextProps = {
/**
* The text to show. Note that this is rendred within a `Text` node.
*/
children: string | React.ReactNode
}

export const AfterText = React.memo(function AfterText({
children,
}: AfterTextProps) {
return (
<Text
noUserSelect
style={Text.style.footnote}
fit={Text.fitValues.wrap}
px={"$edgeInset"}
py={"$captionVerticalMargin"}
color={"$secondaryColor"}
_style={{ flexShrink: 0 }}
>
{children}
</Text>
)
})
183 changes: 183 additions & 0 deletions src/components/Button/Pressable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import React from "react"
import { useTheme } from "tamagui"

import { usePointerEvents } from "../../hooks/usePointerEvents"
import { useShadow as getShadow } from "../../hooks/useShadow"
import { MotionView, ViewContext, type ViewProps } from "../View"

import type { ColorValue } from "../../utils/color"
import type { OnPressWithRef } from "../../utils/types"

export type PressableState = {
isHovered: boolean
isActive: boolean
}

export type ParadigmPressableProps = ViewProps & {
/**
* what happens when the element is pressed?
*
* This is `OnPressWithRef` so its possible to find the element when needed (popups, etc.)
*/
onPress?: OnPressWithRef
/**
* Called whenever hover or active state changes.
*/
onStateChange?: (state: PressableState) => void
/**
* is this element important? Should only be 1 per page.
*/
isPrimary?: boolean
/**
* Does this element have a negative effect (delete, etc.)
*/
isNegative?: boolean
/**
* Is this element floating?
*/
isRaised?: boolean
/**
* is this element disabled?
* This will make `onPress` not work even if defined
*/
isDisabled?: boolean
/**
* Is this element currently in a loading state.
* This will disable `onPress` even if defined
*/
isLoading?: boolean
}

const { all: e1 } = getShadow({
shadowName: "elevation1",
forceBoxShadow: true,
})
const { all: e2 } = getShadow({
shadowName: "elevation2",
forceBoxShadow: true,
})

export const Pressable = ({
children,
onPress,
onStateChange,
isPrimary,
isNegative,
isRaised,
isDisabled: isMarkedDisabled = false,
isLoading,
...otherProps
}: ParadigmPressableProps) => {
const theme = useTheme()
const { color: parentColor } = React.useContext(ViewContext)
const { isHovered, isActive, pointerProps } = usePointerEvents()

React.useEffect(() => {
onStateChange?.({ isHovered, isActive })
}, [isHovered, isActive, onStateChange])
const pressableRef = React.useRef(null)

let backgroundColor: ColorValue

// the button is disabled both when loading and when actively marked disabled
const isDisabled = isMarkedDisabled || isLoading

const buttonState = isDisabled
? isLoading
? "loading"
: "disabled"
: isHovered
? isActive
? "hoverActive"
: "hover"
: isActive
? "active"
: "normal"

// Background Color
const raisedColor = parentColor
? parentColor.toString() !== "$background"
? theme.background
: theme.cardStock
: theme.cardStock

switch (buttonState) {
case "loading":
case "disabled": {
backgroundColor = theme.cardStock
break
}
case "hover": {
backgroundColor = isPrimary
? isNegative
? theme.negativeHover
: theme.primaryHover
: isRaised
? raisedColor
: theme.normalHover
break
}
case "active":
case "hoverActive": {
backgroundColor = isPrimary
? isNegative
? theme.negativeActive
: theme.primaryActive
: isRaised
? raisedColor
: theme.normalActive
break
}
default: {
// normal
if (isPrimary) {
if (isNegative) {
backgroundColor = theme.destructive
} else {
backgroundColor = theme.primary
}
} else {
if (isRaised) {
backgroundColor = raisedColor
} else {
backgroundColor = theme.cardStock
}
}
}
}

return (
<MotionView
ref={pressableRef}
center
noShrink
color={backgroundColor}
_tamaguiProps={{ flexDirection: "row" }}
{...otherProps}
{...pointerProps}
disabled={isDisabled ?? false}
cursor={isDisabled ? "not-allowed" : "pointer"}
variants={{
normal: { filter: "none" },
raised: { y: -1, filter: e1.filter ?? "none", boxShadow: e1.boxShadow },
hover: { y: -3, filter: e2.filter ?? "none", boxShadow: e2.boxShadow },
active: { y: 0, filter: e1.filter ?? "none", boxShadow: e1.boxShadow },
}}
animate={
isRaised && !isDisabled
? isHovered
? isActive
? "active"
: "hover"
: "raised"
: "normal"
}
transition={{ type: "spring", visualDuration: 0.35, bounce: 0.35 }}
onPress={(event) => {
onPress?.({ ref: pressableRef, event })
}}
>
{children}
</MotionView>
)
}
Loading
Loading