@startsimpli/ui 0.4.154 → 0.4.155
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@startsimpli/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.155",
|
|
4
4
|
"description": "Shared UI components package for StartSimpli applications",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"@codemirror/state": "^6.0.0",
|
|
57
57
|
"@codemirror/view": "^6.0.0",
|
|
58
58
|
"@startsimpli/api": "^0.5.68",
|
|
59
|
-
"@startsimpli/
|
|
60
|
-
"@startsimpli/
|
|
59
|
+
"@startsimpli/auth": "^0.4.41",
|
|
60
|
+
"@startsimpli/i18n": "^0.1.3"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"@startsimpli/api": {
|
|
@@ -152,8 +152,8 @@
|
|
|
152
152
|
"tailwindcss": "^3.4.19",
|
|
153
153
|
"tsup": "^8.5.1",
|
|
154
154
|
"typescript": "^6.0.3",
|
|
155
|
-
"@startsimpli/
|
|
156
|
-
"@startsimpli/
|
|
155
|
+
"@startsimpli/realtime": "0.0.2",
|
|
156
|
+
"@startsimpli/i18n": "0.1.3"
|
|
157
157
|
},
|
|
158
158
|
"keywords": [
|
|
159
159
|
"ui",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react'
|
|
3
|
+
import { Switch } from '../switch'
|
|
4
|
+
|
|
5
|
+
describe('Switch', () => {
|
|
6
|
+
it('is a role=switch named by its label, reporting its state', () => {
|
|
7
|
+
render(<Switch checked aria-label="Comeback sequence" />)
|
|
8
|
+
const sw = screen.getByRole('switch', { name: 'Comeback sequence' })
|
|
9
|
+
expect(sw).toHaveAttribute('aria-checked', 'true')
|
|
10
|
+
expect(sw).toHaveAttribute('type', 'button')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('asks for the opposite state on click and stays controlled', () => {
|
|
14
|
+
const onCheckedChange = jest.fn()
|
|
15
|
+
render(<Switch checked={false} onCheckedChange={onCheckedChange} aria-label="x" />)
|
|
16
|
+
const sw = screen.getByRole('switch')
|
|
17
|
+
fireEvent.click(sw)
|
|
18
|
+
expect(onCheckedChange).toHaveBeenCalledWith(true)
|
|
19
|
+
// The caller did not change `checked`, so the switch did not move.
|
|
20
|
+
expect(sw).toHaveAttribute('aria-checked', 'false')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('toggles when the caller updates checked', () => {
|
|
24
|
+
function Harness() {
|
|
25
|
+
const [on, setOn] = useState(false)
|
|
26
|
+
return <Switch checked={on} onCheckedChange={setOn} aria-label="x" />
|
|
27
|
+
}
|
|
28
|
+
render(<Harness />)
|
|
29
|
+
fireEvent.click(screen.getByRole('switch'))
|
|
30
|
+
expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'true')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('does nothing while disabled', () => {
|
|
34
|
+
const onCheckedChange = jest.fn()
|
|
35
|
+
render(<Switch checked={false} disabled onCheckedChange={onCheckedChange} aria-label="x" />)
|
|
36
|
+
fireEvent.click(screen.getByRole('switch'))
|
|
37
|
+
expect(onCheckedChange).not.toHaveBeenCalled()
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Switch: an on/off control that takes effect at once (startsim-r7hws).
|
|
5
|
+
*
|
|
6
|
+
* A native <button role="switch" aria-checked>, so screen readers announce
|
|
7
|
+
* "on"/"off" and Space/Enter toggle it with no extra key handling. Use a
|
|
8
|
+
* Checkbox when the choice is only applied by a later Save.
|
|
9
|
+
*
|
|
10
|
+
* Controlled only: the caller owns `checked`, so a write the server refuses
|
|
11
|
+
* can leave the switch where it was.
|
|
12
|
+
*/
|
|
13
|
+
import * as React from "react"
|
|
14
|
+
|
|
15
|
+
import { cn } from "../../lib/utils"
|
|
16
|
+
|
|
17
|
+
export interface SwitchProps
|
|
18
|
+
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onChange" | "role" | "type"> {
|
|
19
|
+
checked: boolean
|
|
20
|
+
onCheckedChange?: (checked: boolean) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
|
|
24
|
+
({ checked, onCheckedChange, onClick, className, disabled, ...props }, ref) => (
|
|
25
|
+
<button
|
|
26
|
+
ref={ref}
|
|
27
|
+
type="button"
|
|
28
|
+
role="switch"
|
|
29
|
+
aria-checked={checked}
|
|
30
|
+
data-state={checked ? "checked" : "unchecked"}
|
|
31
|
+
disabled={disabled}
|
|
32
|
+
onClick={(e) => {
|
|
33
|
+
onClick?.(e)
|
|
34
|
+
if (!e.defaultPrevented) onCheckedChange?.(!checked)
|
|
35
|
+
}}
|
|
36
|
+
className={cn(
|
|
37
|
+
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
|
|
38
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
39
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
40
|
+
checked ? "bg-primary" : "bg-input",
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<span
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
className={cn(
|
|
48
|
+
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
|
|
49
|
+
checked ? "translate-x-5" : "translate-x-0",
|
|
50
|
+
)}
|
|
51
|
+
/>
|
|
52
|
+
</button>
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
Switch.displayName = "Switch"
|
|
56
|
+
|
|
57
|
+
export { Switch }
|