aporia 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Nico Frey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # aporia
2
+
3
+ A collection of production-quality React components for building configurators - sliders, color pickers, gradient editors, toggles, and more.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install aporia
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { SliderRow, ColorRow, ToggleRow, GradientRow, ThemeProvider } from 'aporia'
15
+ import 'aporia/styles.css'
16
+
17
+ function App() {
18
+ const [intensity, setIntensity] = useState(50)
19
+ const [color, setColor] = useState('#E8470C')
20
+ const [enabled, setEnabled] = useState(false)
21
+
22
+ return (
23
+ <ThemeProvider>
24
+ <SliderRow
25
+ label="Intensity"
26
+ value={intensity}
27
+ min={0}
28
+ max={100}
29
+ step={1}
30
+ onChange={setIntensity}
31
+ />
32
+ <ColorRow
33
+ label="Accent"
34
+ value={color}
35
+ onChange={setColor}
36
+ />
37
+ <ToggleRow
38
+ label="Enabled"
39
+ checked={enabled}
40
+ onChange={setEnabled}
41
+ />
42
+ <GradientRow
43
+ label="Background"
44
+ onChange={(gradient) => console.log(gradient)}
45
+ />
46
+ </ThemeProvider>
47
+ )
48
+ }
49
+ ```
50
+
51
+ ## Components
52
+
53
+ ### SliderRow
54
+
55
+ A polished slider with spring animations, keyboard support, and inline editing.
56
+
57
+ ```tsx
58
+ <SliderRow
59
+ label="Volume"
60
+ value={volume}
61
+ min={0}
62
+ max={100}
63
+ step={1}
64
+ onChange={setVolume}
65
+ fmt={(n) => `${n}%`} // Optional formatter
66
+ />
67
+ ```
68
+
69
+ ### ColorRow
70
+
71
+ Hex color picker with inline editing and native color picker fallback.
72
+
73
+ ```tsx
74
+ <ColorRow
75
+ label="Color"
76
+ value={color}
77
+ onChange={setColor}
78
+ />
79
+ ```
80
+
81
+ ### ToggleRow
82
+
83
+ Accessible toggle switch with keyboard support.
84
+
85
+ ```tsx
86
+ <ToggleRow
87
+ label="Dark Mode"
88
+ checked={isDark}
89
+ onChange={setIsDark}
90
+ />
91
+ ```
92
+
93
+ ### GradientRow
94
+
95
+ Multi-stop gradient editor with shuffle, invert, and auto-distribute controls.
96
+
97
+ ```tsx
98
+ <GradientRow
99
+ label="Gradient"
100
+ initialStops={[
101
+ { color: '#000000', position: 0 },
102
+ { color: '#ffffff', position: 100 },
103
+ ]}
104
+ angle={90}
105
+ onChange={(cssGradient) => console.log(cssGradient)}
106
+ />
107
+ ```
108
+
109
+ ### GradientPicker
110
+
111
+ Lower-level gradient editor component with full control.
112
+
113
+ ```tsx
114
+ import { GradientPicker, stopsToGradient, parseGradient } from 'aporia'
115
+
116
+ <GradientPicker
117
+ stops={stops}
118
+ onChange={setStops}
119
+ />
120
+
121
+ // Utilities
122
+ const css = stopsToGradient(stops, 90) // Convert to CSS
123
+ const stops = parseGradient(css) // Parse CSS gradient
124
+ ```
125
+
126
+ ## Theming
127
+
128
+ Aporia includes built-in dark and light themes. Wrap your app with `ThemeProvider`:
129
+
130
+ ```tsx
131
+ import { ThemeProvider, useTheme } from 'aporia'
132
+
133
+ function App() {
134
+ return (
135
+ <ThemeProvider>
136
+ <YourApp />
137
+ </ThemeProvider>
138
+ )
139
+ }
140
+
141
+ // Access theme in components
142
+ function ThemeToggle() {
143
+ const { theme, toggleTheme } = useTheme()
144
+ return <button onClick={toggleTheme}>{theme}</button>
145
+ }
146
+ ```
147
+
148
+ Keyboard shortcut: `Shift+T` toggles the theme.
149
+
150
+ ## Peer Dependencies
151
+
152
+ Aporia requires these peer dependencies:
153
+
154
+ - `react` >= 18.0.0
155
+ - `react-dom` >= 18.0.0
156
+ - `motion` >= 12.0.0
157
+ - `@base-ui/react` >= 1.0.0
158
+
159
+ ## Development
160
+
161
+ ```bash
162
+ # Install dependencies
163
+ npm install
164
+
165
+ # Start dev server (demo app)
166
+ npm run dev
167
+
168
+ # Build library
169
+ npm run build
170
+
171
+ # Lint
172
+ npm run lint
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,13 @@
1
+ import { ReactNode } from 'react';
2
+ export type Theme = 'dark' | 'light';
3
+ type ThemeContextValue = {
4
+ theme: Theme;
5
+ setTheme: (t: Theme) => void;
6
+ toggleTheme: () => void;
7
+ };
8
+ export declare function ThemeProvider({ children }: {
9
+ children: ReactNode;
10
+ }): import("react/jsx-runtime").JSX.Element;
11
+ export declare function useTheme(): ThemeContextValue;
12
+ export {};
13
+ //# sourceMappingURL=ThemeProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../src/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAGd,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;AAIpC,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;IAC5B,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB,CAAA;AAcD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAkClE;AAED,wBAAgB,QAAQ,sBAMvB"}
@@ -0,0 +1,7 @@
1
+ export type ColorRowProps = {
2
+ label?: string;
3
+ value: string;
4
+ onChange: (hex: string) => void;
5
+ };
6
+ export declare function ColorRow({ label, value, onChange }: ColorRowProps): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=ColorRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorRow.d.ts","sourceRoot":"","sources":["../../src/components/ColorRow.tsx"],"names":[],"mappings":"AAEA,OAAO,gBAAgB,CAAA;AAsBvB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC,CAAA;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,aAAa,2CAkI3E"}
@@ -0,0 +1,19 @@
1
+ export type GradientStop = {
2
+ color: string;
3
+ };
4
+ export type GradientPickerProps = {
5
+ /** Array of gradient stops (colors only, positions auto-distributed) */
6
+ stops: GradientStop[];
7
+ /** Called when stops change */
8
+ onChange: (stops: GradientStop[]) => void;
9
+ /** Gradient angle in degrees, default 90 (left to right) */
10
+ angle?: number;
11
+ };
12
+ /** Generate CSS linear-gradient from stops with even distribution */
13
+ export declare function stopsToGradient(stops: GradientStop[], angle?: number): string;
14
+ /** Parse a linear-gradient string into stops */
15
+ export declare function parseGradient(gradient: string): GradientStop[];
16
+ /** Default 6 colors for gradient picker (dark to light, top to bottom) */
17
+ export declare const DEFAULT_GRADIENT_STOPS: GradientStop[];
18
+ export declare function GradientPicker({ stops, onChange }: GradientPickerProps): import("react/jsx-runtime").JSX.Element;
19
+ //# sourceMappingURL=GradientPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradientPicker.d.ts","sourceRoot":"","sources":["../../src/components/GradientPicker.tsx"],"names":[],"mappings":"AASA,OAAO,sBAAsB,CAAA;AAE7B,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,wEAAwE;IACxE,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,+BAA+B;IAC/B,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAA;IACzC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAoFD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,SAAK,GAAG,MAAM,CAWzE;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAmB9D;AAED,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,EAAE,YAAY,EAOhD,CAAA;AA6HD,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAyFtE"}
@@ -0,0 +1,12 @@
1
+ import { GradientStop } from './GradientPicker';
2
+ export type GradientRowProps = {
3
+ label?: string;
4
+ /** Initial gradient stops - defaults to 6 teal-to-dark colors */
5
+ initialStops?: GradientStop[];
6
+ /** Called when gradient changes */
7
+ onChange?: (gradient: string) => void;
8
+ /** Gradient angle in degrees, default 90 */
9
+ angle?: number;
10
+ };
11
+ export declare function GradientRow({ label, initialStops, onChange, angle }: GradientRowProps): import("react/jsx-runtime").JSX.Element;
12
+ //# sourceMappingURL=GradientRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradientRow.d.ts","sourceRoot":"","sources":["../../src/components/GradientRow.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA2D,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC7G,OAAO,mBAAmB,CAAA;AAE1B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,YAAY,CAAC,EAAE,YAAY,EAAE,CAAA;IAC7B,mCAAmC;IACnC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAkB,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAU,EAAE,EAAE,gBAAgB,2CA0CvG"}
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ export declare function SliderOverlapDebugProvider({ children }: {
3
+ children: ReactNode;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ export declare function useSliderOverlapDebugEnabled(): boolean;
6
+ //# sourceMappingURL=SliderOverlapDebug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderOverlapDebug.d.ts","sourceRoot":"","sources":["../../src/components/SliderOverlapDebug.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAKd,wBAAgB,0BAA0B,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAoB/E;AAED,wBAAgB,4BAA4B,YAE3C"}
@@ -0,0 +1,11 @@
1
+ export type SliderRowProps = {
2
+ label: string;
3
+ value: number;
4
+ min: number;
5
+ max: number;
6
+ step: number;
7
+ onChange: (value: number) => void;
8
+ fmt?: (value: number) => string;
9
+ };
10
+ export declare function SliderRow({ label, value, min, max, step, onChange, fmt, }: SliderRowProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=SliderRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderRow.d.ts","sourceRoot":"","sources":["../../src/components/SliderRow.tsx"],"names":[],"mappings":"AAKA,OAAO,iBAAiB,CAAA;AAuDxB,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CAChC,CAAA;AAmDD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,GAAG,EACH,GAAG,EACH,IAAI,EACJ,QAAQ,EACR,GAAG,GACJ,EAAE,cAAc,2CA6fhB"}
@@ -0,0 +1,16 @@
1
+ import { PopoverTrigger } from '@base-ui/react/popover';
2
+ import { ReactNode } from 'react';
3
+ export type SwatchPopoverRenderTrigger = PopoverTrigger.Props['render'];
4
+ type SwatchPopoverProps = {
5
+ title?: string;
6
+ renderTrigger: NonNullable<SwatchPopoverRenderTrigger>;
7
+ children: ReactNode;
8
+ };
9
+ /**
10
+ * Base UI Popover anchored to a swatch: opens below, aligned to the inline end (bottom-trailing in LTR).
11
+ * `modal={true}` is required for the internal backdrop (blocks clicks/scroll on the rest of the page).
12
+ * `modal="trap-focus"` does not mount that layer, so controls underneath stayed clickable.
13
+ */
14
+ export declare function SwatchPopover({ title, renderTrigger, children }: SwatchPopoverProps): import("react/jsx-runtime").JSX.Element;
15
+ export {};
16
+ //# sourceMappingURL=SwatchPopover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwatchPopover.d.ts","sourceRoot":"","sources":["../../src/components/SwatchPopover.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,qBAAqB,CAAA;AAE5B,MAAM,MAAM,0BAA0B,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;AAEvE,KAAK,kBAAkB,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,WAAW,CAAC,0BAA0B,CAAC,CAAA;IACtD,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CA2BnF"}
@@ -0,0 +1,7 @@
1
+ export type ToggleRowProps = {
2
+ label: string;
3
+ checked: boolean;
4
+ onChange: (next: boolean) => void;
5
+ };
6
+ export declare function ToggleRow({ label, checked, onChange }: ToggleRowProps): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=ToggleRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleRow.d.ts","sourceRoot":"","sources":["../../src/components/ToggleRow.tsx"],"names":[],"mappings":"AACA,OAAO,iBAAiB,CAAA;AAExB,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAClC,CAAA;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,cAAc,2CAiCrE"}
@@ -0,0 +1,17 @@
1
+ export { SliderRow } from './components/SliderRow';
2
+ export type { SliderRowProps } from './components/SliderRow';
3
+ export { ColorRow } from './components/ColorRow';
4
+ export type { ColorRowProps } from './components/ColorRow';
5
+ export { ToggleRow } from './components/ToggleRow';
6
+ export type { ToggleRowProps } from './components/ToggleRow';
7
+ export { GradientRow } from './components/GradientRow';
8
+ export type { GradientRowProps } from './components/GradientRow';
9
+ export { GradientPicker, stopsToGradient, parseGradient, DEFAULT_GRADIENT_STOPS } from './components/GradientPicker';
10
+ export type { GradientStop, GradientPickerProps } from './components/GradientPicker';
11
+ export { SwatchPopover } from './components/SwatchPopover';
12
+ export type { SwatchPopoverRenderTrigger } from './components/SwatchPopover';
13
+ export { ThemeProvider, useTheme } from './ThemeProvider';
14
+ export type { Theme } from './ThemeProvider';
15
+ export { SliderOverlapDebugProvider, useSliderOverlapDebugEnabled } from './components/SliderOverlapDebug';
16
+ export { isTextInputTarget } from './utils/isTextInputTarget';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAEhE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpH,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEpF,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;AAG5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACzD,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAG1G,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA"}