aporia 0.2.0 → 0.2.5
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/README.md +21 -8
- package/dist/ThemeProvider.d.ts.map +1 -1
- package/dist/components/Category.d.ts.map +1 -1
- package/dist/components/SelectRow.d.ts +17 -0
- package/dist/components/SelectRow.d.ts.map +1 -0
- package/dist/{style.css → index.css} +420 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +147 -11
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -8,11 +8,24 @@ A collection of production-quality React components for building configurators -
|
|
|
8
8
|
npm install aporia
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Import **`aporia/styles.css` once** in your app entry (for example `main.tsx`). If you use Tailwind or another global reset, import Aporia’s stylesheet **after** those layers so Aporia’s opinionated panel / popover typography and control chrome win predictable conflicts.
|
|
12
|
+
|
|
13
|
+
## Maintainers: package demo + consumer sandbox
|
|
14
|
+
|
|
15
|
+
If you keep a sibling app (for example `../aporia-test`) next to this repo:
|
|
16
|
+
|
|
17
|
+
1. **Canonical UI (this repo)** — `npm run dev` starts the **Vite demo** (`--mode demo`, default port **5178**). That is the reference layout: white page shell (`var(--color-page)`), `Panel` capped at **360px** wide like `src/App.css`.
|
|
18
|
+
2. **NPM-style consumer** — in the sibling app, depend on `file:../aporia`, run `npm run dev` there (this workspace uses port **5173** for the consumer). After library changes, run `npm run sync-lib` inside the consumer to rebuild `aporia` and refresh the `file:` install.
|
|
19
|
+
3. **From the parent folder** — with both repos under the same parent directory, `npm run dev:package` and `npm run dev:consumer` run each app; `npm run sync:consumer` rebuilds the library and reinstalls into the consumer.
|
|
20
|
+
|
|
21
|
+
Publishing for end users: bump `version`, run `npm run build`, then `npm publish`. Consumers should use a normal semver range (for example `^0.2.5`) and `import 'aporia/styles.css'`. The `prepublishOnly` script runs `build` automatically on publish. Until you publish, sibling apps can use `file:../aporia` and `npm run sync-lib` after edits — **no publish required** for local reflection.
|
|
22
|
+
|
|
11
23
|
## Usage
|
|
12
24
|
|
|
13
25
|
The usual setup is a **Panel** with one or more **Category** blocks, each containing rows (`SliderRow`, `ColorRow`, etc.). The package default export is `Panel`, so you can import it as the default or by name.
|
|
14
26
|
|
|
15
27
|
```tsx
|
|
28
|
+
import { useState } from 'react'
|
|
16
29
|
import Panel, { Category, SliderRow, ColorRow, ToggleRow, GradientRow, ThemeProvider } from 'aporia'
|
|
17
30
|
import 'aporia/styles.css'
|
|
18
31
|
|
|
@@ -45,7 +58,7 @@ function App() {
|
|
|
45
58
|
}
|
|
46
59
|
```
|
|
47
60
|
|
|
48
|
-
|
|
61
|
+
Use `Panel` (and usually `Category`) for any real configurator surface so spacing, typography, and the black card shell stay consistent. Rows still work as leaf nodes, but they are designed to live inside that shell.
|
|
49
62
|
|
|
50
63
|
## Components
|
|
51
64
|
|
|
@@ -132,7 +145,9 @@ const stops = parseGradient(css) // Parse CSS gradient
|
|
|
132
145
|
|
|
133
146
|
## Theming
|
|
134
147
|
|
|
135
|
-
Aporia
|
|
148
|
+
Aporia ships a **dark** visual system: the **Panel** surface is always `#000000` with light text, and `color-scheme: dark` is scoped to the panel and floating pickers only so your host page (light theme, marketing site, etc.) is not forced into document-wide dark UA chrome. CSS variables remain on `:root` so portaled popovers still inherit them.
|
|
149
|
+
|
|
150
|
+
`ThemeProvider` is for **React context** (`useTheme`) only; it does not mutate `<html>` or set global `data-theme`.
|
|
136
151
|
|
|
137
152
|
```tsx
|
|
138
153
|
import { ThemeProvider, useTheme } from 'aporia'
|
|
@@ -145,15 +160,13 @@ function App() {
|
|
|
145
160
|
)
|
|
146
161
|
}
|
|
147
162
|
|
|
148
|
-
//
|
|
149
|
-
function
|
|
150
|
-
const { theme
|
|
151
|
-
return <
|
|
163
|
+
// `theme` is `'dark'` today; useful for future light mode without changing call sites.
|
|
164
|
+
function ThemeLabel() {
|
|
165
|
+
const { theme } = useTheme()
|
|
166
|
+
return <span>{theme}</span>
|
|
152
167
|
}
|
|
153
168
|
```
|
|
154
169
|
|
|
155
|
-
Keyboard shortcut: `Shift+T` toggles the theme.
|
|
156
|
-
|
|
157
170
|
## Peer Dependencies
|
|
158
171
|
|
|
159
172
|
Aporia requires these peer dependencies:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../src/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../src/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjE,MAAM,MAAM,KAAK,GAAG,MAAM,CAAA;AAE1B,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,KAAK,CAAA;CACb,CAAA;AAID,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAQlE;AAED,wBAAgB,QAAQ,sBAMvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Category.d.ts","sourceRoot":"","sources":["../../src/components/Category.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Category.d.ts","sourceRoot":"","sources":["../../src/components/Category.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAGd,OAAO,gBAAgB,CAAA;AAavB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,SAAS,CAAA;IAChB,QAAQ,EAAE,SAAS,CAAA;IACnB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAA;IAClD,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,CAAA;IACpD,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,gBAAgB,EAChB,SAAS,EAAE,aAAa,EACxB,iBAAiB,EACjB,gBAAwB,EACxB,SAAS,GACV,EAAE,aAAa,2CAqJf"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type SelectRowOption = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
};
|
|
5
|
+
export type SelectRowProps = {
|
|
6
|
+
label: string;
|
|
7
|
+
options: readonly SelectRowOption[];
|
|
8
|
+
/** Controlled value; `null` shows the placeholder. */
|
|
9
|
+
value: string | null;
|
|
10
|
+
onChange: (value: string) => void;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Optional form field name (hidden input). */
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function SelectRow({ label, options, value, onChange, placeholder, disabled: disabledProp, name, }: SelectRowProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=SelectRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectRow.d.ts","sourceRoot":"","sources":["../../src/components/SelectRow.tsx"],"names":[],"mappings":"AAGA,OAAO,iBAAiB,CAAA;AAExB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,SAAS,eAAe,EAAE,CAAA;IACnC,sDAAsD;IACtD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,OAAO,EACP,KAAK,EACL,QAAQ,EACR,WAAuB,EACvB,QAAQ,EAAE,YAAY,EACtB,IAAI,GACL,EAAE,cAAc,2CA8FhB"}
|
|
@@ -1,9 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Theme tokens — dark mode only.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Tokens live on :root so portaled popovers (mounted under <body>) still inherit variables.
|
|
7
|
+
* Do not set `color-scheme` here — that would affect the entire host document (scrollbars,
|
|
8
|
+
* native controls outside Aporia). `color-scheme: dark` is applied only on Panel and popups.
|
|
9
|
+
*/
|
|
10
|
+
:root {
|
|
11
|
+
/* App shell */
|
|
12
|
+
--color-page: #ffffff;
|
|
13
|
+
--color-text: rgba(255, 255, 255, 0.87);
|
|
14
|
+
--color-muted: rgba(255, 255, 255, 0.45);
|
|
15
|
+
|
|
16
|
+
/* Slider card (full pill) */
|
|
17
|
+
--slider-surface: rgba(255, 255, 255, 0.05);
|
|
18
|
+
--slider-surface-active: rgba(255, 255, 255, 0.08);
|
|
19
|
+
--slider-rim: rgba(255, 255, 255, 0.06);
|
|
20
|
+
|
|
21
|
+
/* Filled track (left portion) */
|
|
22
|
+
--slider-track: rgba(255, 255, 255, 0.11);
|
|
23
|
+
--slider-track-active: rgba(255, 255, 255, 0.18);
|
|
24
|
+
/* ButtonRow / pointer-down on track-like controls */
|
|
25
|
+
--slider-track-pressed: rgba(255, 255, 255, 0.26);
|
|
26
|
+
|
|
27
|
+
/* Thumb */
|
|
28
|
+
--slider-thumb: rgba(255, 255, 255, 0.7);
|
|
29
|
+
--slider-thumb-dragging: #ffffff;
|
|
30
|
+
|
|
31
|
+
/* Typography */
|
|
32
|
+
--slider-text-muted: rgba(255, 255, 255, 0.7);
|
|
33
|
+
--slider-text: #ffffff;
|
|
34
|
+
/*
|
|
35
|
+
* UI font for Panel, rows, and portaled UI (popover content inherits from :root,
|
|
36
|
+
* not from Panel — without a default, `inherit` resolves to the browser body font).
|
|
37
|
+
* Override anytime: html { --aporia-font-family: 'Inter', system-ui, sans-serif; }
|
|
38
|
+
*/
|
|
39
|
+
--aporia-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
40
|
+
'Helvetica Neue', Arial, sans-serif;
|
|
41
|
+
|
|
42
|
+
/* Fixed UI rhythm (px): not tied to host `html { font-size: … }` / rem scaling). */
|
|
43
|
+
--aporia-ui-font-size: 14px;
|
|
44
|
+
--aporia-ui-line-height: 1.25;
|
|
45
|
+
|
|
46
|
+
/* Ticks (base color × layer opacity ≈ dark appearance) */
|
|
47
|
+
--slider-tick: rgba(255, 255, 255, 0.32);
|
|
48
|
+
--slider-tick-layer-opacity: 0.3;
|
|
49
|
+
|
|
50
|
+
/* Thumb opacity when row not hovered */
|
|
51
|
+
--slider-thumb-idle-opacity: 0;
|
|
52
|
+
|
|
53
|
+
/* Value field selection (same in both themes per spec) */
|
|
54
|
+
--slider-value-selection-bg: #ffffff;
|
|
55
|
+
--slider-value-selection-fg: #000000;
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* Toggle inner thumb: must match how the *row* reads, but stay opaque — the ON
|
|
59
|
+
* track is solid white; semi-transparent --slider-surface would wash out and
|
|
60
|
+
* hide the thumb. These ≈ 5% / 8% white on black, same as the row visually.
|
|
61
|
+
*/
|
|
62
|
+
--toggle-thumb-row-bg: #0d0d0d;
|
|
63
|
+
--toggle-thumb-row-bg-hover: #141414;
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* Swatch popover: opaque fill so the panel reads on #000 (rows use translucent rgba).
|
|
67
|
+
* #0a0a0a matches Figma design spec.
|
|
68
|
+
*/
|
|
69
|
+
--swatch-popover-surface: #141414;
|
|
70
|
+
--swatch-popover-bg: #0a0a0a;
|
|
71
|
+
--swatch-popover-rim: rgba(255, 255, 255, 0.12);
|
|
72
|
+
|
|
73
|
+
/* Shift+D debug overlays */
|
|
74
|
+
--slider-debug-label-tint: rgba(255, 0, 160, 0.18);
|
|
75
|
+
--slider-debug-value-tint: rgba(255, 200, 0, 0.2);
|
|
76
|
+
--slider-debug-dom-label: rgba(0, 255, 140, 0.9);
|
|
77
|
+
--slider-debug-dom-value: rgba(80, 180, 255, 0.95);
|
|
78
|
+
--slider-debug-dom-shadow: rgba(0, 0, 0, 0.35);
|
|
79
|
+
}
|
|
1
80
|
/* Shell for grouped controls: solid black card, generous radius, inset padding. */
|
|
2
81
|
|
|
3
82
|
.aporiaPanel {
|
|
4
83
|
box-sizing: border-box;
|
|
5
84
|
width: 100%;
|
|
6
85
|
min-width: 0;
|
|
86
|
+
/* Hug content: avoid stretching to fill a flex/grid parent’s unused vertical space. */
|
|
87
|
+
flex: 0 0 auto;
|
|
88
|
+
height: auto;
|
|
89
|
+
min-height: 0;
|
|
90
|
+
max-height: none;
|
|
91
|
+
align-self: stretch;
|
|
92
|
+
/* Typography + metrics: see `aporia-surfaces.css` (imported after components). */
|
|
93
|
+
/* Always read as the black configurator card, independent of host `color` / light UI. */
|
|
94
|
+
color: var(--slider-text);
|
|
95
|
+
color-scheme: dark;
|
|
7
96
|
background-color: #000000;
|
|
8
97
|
border-radius: 24px;
|
|
9
98
|
padding: 16px;
|
|
@@ -15,6 +104,7 @@
|
|
|
15
104
|
0 6px 14px 0 rgba(0, 0, 0, 0.09);
|
|
16
105
|
display: flex;
|
|
17
106
|
flex-direction: column;
|
|
107
|
+
gap: 8px;
|
|
18
108
|
align-items: stretch;
|
|
19
109
|
justify-content: flex-start;
|
|
20
110
|
align-content: flex-start;
|
|
@@ -22,7 +112,8 @@
|
|
|
22
112
|
.category {
|
|
23
113
|
display: flex;
|
|
24
114
|
flex-direction: column;
|
|
25
|
-
|
|
115
|
+
/* Keep in sync with CATEGORY_STACK_GAP_PX in Category.tsx (motion cancels this when collapsed). */
|
|
116
|
+
gap: 8px;
|
|
26
117
|
min-width: 0;
|
|
27
118
|
}
|
|
28
119
|
|
|
@@ -134,6 +225,7 @@
|
|
|
134
225
|
margin: 0;
|
|
135
226
|
flex: 1;
|
|
136
227
|
min-width: 0;
|
|
228
|
+
font-family: var(--aporia-font-family);
|
|
137
229
|
font-size: 12px;
|
|
138
230
|
font-weight: 500;
|
|
139
231
|
letter-spacing: 0.08em;
|
|
@@ -145,15 +237,17 @@
|
|
|
145
237
|
|
|
146
238
|
.categoryBody {
|
|
147
239
|
min-width: 0;
|
|
148
|
-
padding-bottom: 4px;
|
|
149
240
|
}
|
|
150
241
|
|
|
151
|
-
/*
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
242
|
+
/* Padding lives inside the height animation so it never springs on its own (8px + Panel gap = 16px between categories). */
|
|
243
|
+
.categoryBodyInner {
|
|
244
|
+
min-width: 0;
|
|
245
|
+
padding-bottom: 8px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Last category among siblings: no extra bottom inset (panel padding handles the card edge). */
|
|
249
|
+
.category:not(:has(~ .category)) .categoryBodyInner {
|
|
250
|
+
padding-bottom: 0;
|
|
157
251
|
}
|
|
158
252
|
|
|
159
253
|
.category[data-disabled="true"] .categoryBody {
|
|
@@ -380,6 +474,7 @@
|
|
|
380
474
|
position: absolute;
|
|
381
475
|
inset: 0;
|
|
382
476
|
right: auto;
|
|
477
|
+
z-index: 0;
|
|
383
478
|
background: var(--slider-track);
|
|
384
479
|
border-radius: 12px;
|
|
385
480
|
pointer-events: none;
|
|
@@ -562,6 +657,8 @@
|
|
|
562
657
|
flex-direction: column;
|
|
563
658
|
width: 190px;
|
|
564
659
|
box-sizing: border-box;
|
|
660
|
+
color-scheme: dark;
|
|
661
|
+
font-family: var(--aporia-font-family, inherit);
|
|
565
662
|
background: rgba(10, 10, 10, 0.8);
|
|
566
663
|
backdrop-filter: blur(20px);
|
|
567
664
|
border: 0.5px solid rgba(255, 255, 255, 0.06);
|
|
@@ -655,10 +752,6 @@
|
|
|
655
752
|
}
|
|
656
753
|
|
|
657
754
|
/* Hex value - uses ValueInput component */
|
|
658
|
-
.colorPickerHex {
|
|
659
|
-
font-family: 'SF Compact Rounded', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
755
|
.colorPickerHex .valueInputField {
|
|
663
756
|
width: 72px;
|
|
664
757
|
}
|
|
@@ -667,7 +760,6 @@
|
|
|
667
760
|
display: flex;
|
|
668
761
|
align-items: center;
|
|
669
762
|
gap: 10px;
|
|
670
|
-
font-family: 'SF Compact Rounded', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
671
763
|
font-size: 14px;
|
|
672
764
|
line-height: normal;
|
|
673
765
|
letter-spacing: 0.28px;
|
|
@@ -727,7 +819,6 @@
|
|
|
727
819
|
border-radius: 9px;
|
|
728
820
|
background: transparent;
|
|
729
821
|
color: rgba(255, 255, 255, 0.7);
|
|
730
|
-
font-family: 'SF Compact Rounded', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
731
822
|
font-size: 14px;
|
|
732
823
|
line-height: normal;
|
|
733
824
|
letter-spacing: 0.28px;
|
|
@@ -772,6 +863,8 @@
|
|
|
772
863
|
.swatchPopoverPopup {
|
|
773
864
|
position: relative;
|
|
774
865
|
z-index: 1;
|
|
866
|
+
color-scheme: dark;
|
|
867
|
+
font-family: var(--aporia-font-family, inherit);
|
|
775
868
|
min-width: 190px;
|
|
776
869
|
max-width: min(320px, calc(100vw - 24px));
|
|
777
870
|
padding: 0;
|
|
@@ -1043,9 +1136,14 @@
|
|
|
1043
1136
|
-moz-user-select: none;
|
|
1044
1137
|
-webkit-user-drag: none;
|
|
1045
1138
|
width: 100%;
|
|
1046
|
-
font:
|
|
1139
|
+
font-family: var(--aporia-font-family);
|
|
1140
|
+
font-size: var(--aporia-ui-font-size);
|
|
1141
|
+
font-weight: 400;
|
|
1142
|
+
font-style: normal;
|
|
1143
|
+
line-height: var(--aporia-ui-line-height);
|
|
1144
|
+
letter-spacing: normal;
|
|
1047
1145
|
text-align: left;
|
|
1048
|
-
color:
|
|
1146
|
+
color: var(--slider-text-muted);
|
|
1049
1147
|
}
|
|
1050
1148
|
|
|
1051
1149
|
.toggleCard:hover {
|
|
@@ -1135,11 +1233,263 @@
|
|
|
1135
1233
|
.toggleCard[data-on='true'] .toggleSwitch__thumb {
|
|
1136
1234
|
transform: translateX(6px);
|
|
1137
1235
|
}
|
|
1236
|
+
/* Trigger: same geometry as SliderRow; card fill matches .sliderCard (--slider-surface). */
|
|
1237
|
+
|
|
1238
|
+
.selectRowWrap {
|
|
1239
|
+
width: 100%;
|
|
1240
|
+
max-width: 100%;
|
|
1241
|
+
min-width: 0;
|
|
1242
|
+
position: relative;
|
|
1243
|
+
overflow: visible;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.selectRowWrap[data-disabled="true"] {
|
|
1247
|
+
opacity: 0.45;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
.selectRowWrap[data-disabled="true"] .selectCard {
|
|
1251
|
+
pointer-events: none;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.selectCard {
|
|
1255
|
+
position: relative;
|
|
1256
|
+
width: 100%;
|
|
1257
|
+
height: 37px;
|
|
1258
|
+
margin: 0;
|
|
1259
|
+
border: none;
|
|
1260
|
+
border-radius: 12px;
|
|
1261
|
+
background: var(--slider-surface);
|
|
1262
|
+
box-shadow: inset 0 0 0 0.5px var(--slider-rim);
|
|
1263
|
+
overflow: hidden;
|
|
1264
|
+
transition: background-color 0.2s ease-out;
|
|
1265
|
+
cursor: pointer;
|
|
1266
|
+
display: flex;
|
|
1267
|
+
align-items: center;
|
|
1268
|
+
padding: 10px 12px;
|
|
1269
|
+
box-sizing: border-box;
|
|
1270
|
+
font-family: var(--aporia-font-family);
|
|
1271
|
+
font-size: var(--aporia-ui-font-size);
|
|
1272
|
+
font-weight: 400;
|
|
1273
|
+
font-style: normal;
|
|
1274
|
+
line-height: var(--aporia-ui-line-height);
|
|
1275
|
+
letter-spacing: normal;
|
|
1276
|
+
text-align: left;
|
|
1277
|
+
color: var(--slider-text-muted);
|
|
1278
|
+
user-select: none;
|
|
1279
|
+
-webkit-user-select: none;
|
|
1280
|
+
-moz-user-select: none;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
.selectCard:hover:not(:disabled) {
|
|
1284
|
+
background: var(--slider-surface-active);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
.selectCard:focus {
|
|
1288
|
+
outline: none;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
.selectCard:focus-visible {
|
|
1292
|
+
outline: 2px solid var(--slider-text-muted);
|
|
1293
|
+
outline-offset: 2px;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
.selectCard[data-popup-open="true"] {
|
|
1297
|
+
background: var(--slider-surface-active);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
.selectCard:active:not(:disabled) {
|
|
1301
|
+
background: var(--slider-surface-active);
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
.selectLabel {
|
|
1305
|
+
position: relative;
|
|
1306
|
+
font-size: 14px;
|
|
1307
|
+
font-weight: 400;
|
|
1308
|
+
color: var(--slider-text-muted);
|
|
1309
|
+
letter-spacing: 0.28px;
|
|
1310
|
+
flex: 1;
|
|
1311
|
+
min-width: 0;
|
|
1312
|
+
z-index: 2;
|
|
1313
|
+
pointer-events: none;
|
|
1314
|
+
transition: color 0.2s ease-out;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
.selectCard:hover:not(:disabled) .selectLabel,
|
|
1318
|
+
.selectCard[data-popup-open="true"] .selectLabel {
|
|
1319
|
+
color: var(--slider-text);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
.selectValueZone {
|
|
1323
|
+
position: absolute;
|
|
1324
|
+
top: 0;
|
|
1325
|
+
right: 0;
|
|
1326
|
+
height: 100%;
|
|
1327
|
+
z-index: 3;
|
|
1328
|
+
display: flex;
|
|
1329
|
+
align-items: center;
|
|
1330
|
+
justify-content: flex-end;
|
|
1331
|
+
gap: 6px;
|
|
1332
|
+
padding-right: 12px;
|
|
1333
|
+
min-width: 72px;
|
|
1334
|
+
max-width: 50%;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
.selectValue {
|
|
1338
|
+
font-size: 14px;
|
|
1339
|
+
font-weight: 400;
|
|
1340
|
+
letter-spacing: 0.28px;
|
|
1341
|
+
color: var(--slider-text);
|
|
1342
|
+
white-space: nowrap;
|
|
1343
|
+
overflow: hidden;
|
|
1344
|
+
text-overflow: ellipsis;
|
|
1345
|
+
min-width: 0;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
.selectValue[data-placeholder] {
|
|
1349
|
+
color: var(--slider-text-muted);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
.selectIcon {
|
|
1353
|
+
display: flex;
|
|
1354
|
+
flex-shrink: 0;
|
|
1355
|
+
color: var(--slider-text-muted);
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.selectCard:hover:not(:disabled) .selectIcon,
|
|
1359
|
+
.selectCard[data-popup-open="true"] .selectIcon {
|
|
1360
|
+
color: var(--slider-text-muted);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
.selectChevronSvg {
|
|
1364
|
+
display: block;
|
|
1365
|
+
transition: transform 0.2s ease-out;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/* Flip with React `menuOpen` (onOpenChange) so it tracks open immediately, not only after Base UI’s popup-open paint. */
|
|
1369
|
+
.selectCard[data-menu-open="true"] .selectChevronSvg {
|
|
1370
|
+
transform: rotate(180deg);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
.selectPortal {
|
|
1374
|
+
position: relative;
|
|
1375
|
+
z-index: 200000;
|
|
1376
|
+
isolation: isolate;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
.selectPositioner {
|
|
1380
|
+
z-index: 0;
|
|
1381
|
+
box-sizing: border-box;
|
|
1382
|
+
/* At least as wide as the row — set inline on portal as --select-anchor-width */
|
|
1383
|
+
min-width: var(--select-anchor-width, 0px);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/* Base UI scroll nudge controls (▲ / ▼) — hide even if present (siblings of popup in the portal). */
|
|
1387
|
+
.selectPortal [data-direction="up"],
|
|
1388
|
+
.selectPortal [data-direction="down"],
|
|
1389
|
+
.selectPositioner [data-direction="up"],
|
|
1390
|
+
.selectPositioner [data-direction="down"] {
|
|
1391
|
+
display: none !important;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
.selectPopup {
|
|
1395
|
+
box-sizing: border-box;
|
|
1396
|
+
width: 100%;
|
|
1397
|
+
min-width: 0;
|
|
1398
|
+
color-scheme: dark;
|
|
1399
|
+
font-family: var(--aporia-font-family, inherit);
|
|
1400
|
+
max-width: min(320px, calc(100vw - 24px));
|
|
1401
|
+
padding: 4px;
|
|
1402
|
+
border-radius: 12px;
|
|
1403
|
+
background: var(--swatch-popover-bg);
|
|
1404
|
+
box-shadow: inset 0 0 0 0.5px var(--swatch-popover-rim);
|
|
1405
|
+
color: var(--slider-text);
|
|
1406
|
+
outline: none;
|
|
1407
|
+
/* Popover-style motion; anchor to trailing edge (align end / SwatchPopover). */
|
|
1408
|
+
transform-origin: top right;
|
|
1409
|
+
opacity: 1;
|
|
1410
|
+
transform: translateY(0) scale(1);
|
|
1411
|
+
transition:
|
|
1412
|
+
opacity 0.2s ease-out,
|
|
1413
|
+
transform 0.22s cubic-bezier(0.16, 1, 0.3, 1);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.selectPopup[data-starting-style],
|
|
1417
|
+
.selectPopup[data-ending-style] {
|
|
1418
|
+
opacity: 0;
|
|
1419
|
+
transform: translateY(-6px) scale(0.97);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.selectList {
|
|
1423
|
+
display: flex;
|
|
1424
|
+
flex-direction: column;
|
|
1425
|
+
gap: 0;
|
|
1426
|
+
max-height: min(280px, 45vh);
|
|
1427
|
+
overflow-y: auto;
|
|
1428
|
+
padding: 0;
|
|
1429
|
+
min-width: 0;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
.selectItem {
|
|
1433
|
+
position: relative;
|
|
1434
|
+
margin: 0;
|
|
1435
|
+
/* Match SliderRow card: 10px vertical padding + ~17px line = 37px (line-height caps text box). */
|
|
1436
|
+
height: 37px;
|
|
1437
|
+
box-sizing: border-box;
|
|
1438
|
+
padding: 10px 8px;
|
|
1439
|
+
border: none;
|
|
1440
|
+
border-radius: 8px;
|
|
1441
|
+
background: transparent;
|
|
1442
|
+
font-family: var(--aporia-font-family);
|
|
1443
|
+
font-size: var(--aporia-ui-font-size);
|
|
1444
|
+
font-weight: 400;
|
|
1445
|
+
font-style: normal;
|
|
1446
|
+
line-height: 17px;
|
|
1447
|
+
letter-spacing: 0.02em;
|
|
1448
|
+
color: rgba(255, 255, 255, 0.7);
|
|
1449
|
+
cursor: pointer;
|
|
1450
|
+
text-align: left;
|
|
1451
|
+
display: flex;
|
|
1452
|
+
align-items: center;
|
|
1453
|
+
width: 100%;
|
|
1454
|
+
transition:
|
|
1455
|
+
background-color 0.15s ease-out,
|
|
1456
|
+
color 0.15s ease-out;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/* Selected / highlighted visuals: see `aporia-surfaces.css` (host `[role=option]` overrides). */
|
|
1460
|
+
|
|
1461
|
+
.selectItem[data-disabled] {
|
|
1462
|
+
opacity: 0.45;
|
|
1463
|
+
cursor: default;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
.selectItemText {
|
|
1467
|
+
flex: 1;
|
|
1468
|
+
min-width: 0;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1472
|
+
.selectPopup {
|
|
1473
|
+
transition-duration: 0.1s;
|
|
1474
|
+
transition-property: opacity;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
.selectPopup[data-starting-style],
|
|
1478
|
+
.selectPopup[data-ending-style] {
|
|
1479
|
+
transform: none;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
.selectChevronSvg {
|
|
1483
|
+
transition: none;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1138
1486
|
/* Container - exact Figma specs */
|
|
1139
1487
|
.gradientPicker {
|
|
1140
1488
|
display: flex;
|
|
1141
1489
|
flex-direction: column;
|
|
1142
1490
|
width: 190px;
|
|
1491
|
+
color-scheme: dark;
|
|
1492
|
+
font-family: var(--aporia-font-family, inherit);
|
|
1143
1493
|
background: #0a0a0a;
|
|
1144
1494
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
1145
1495
|
border-radius: 12px;
|
|
@@ -1354,3 +1704,57 @@
|
|
|
1354
1704
|
outline: 2px solid var(--slider-text-muted);
|
|
1355
1705
|
outline-offset: 2px;
|
|
1356
1706
|
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Host isolation: consumer apps often scale `rem`, reset `button`, or style generic
|
|
1709
|
+
* `[role="option"]` / `[type="range"]`. These rules sit after component CSS and restore
|
|
1710
|
+
* Aporia’s intended metrics on the panel and on portaled surfaces (not under `.aporiaPanel`).
|
|
1711
|
+
*/
|
|
1712
|
+
|
|
1713
|
+
.aporiaPanel,
|
|
1714
|
+
.swatchPopoverPopup,
|
|
1715
|
+
.selectPopup,
|
|
1716
|
+
.gradientPicker,
|
|
1717
|
+
.colorPicker {
|
|
1718
|
+
font-family: var(--aporia-font-family);
|
|
1719
|
+
font-size: var(--aporia-ui-font-size);
|
|
1720
|
+
font-weight: 400;
|
|
1721
|
+
font-style: normal;
|
|
1722
|
+
line-height: var(--aporia-ui-line-height);
|
|
1723
|
+
letter-spacing: normal;
|
|
1724
|
+
-webkit-font-smoothing: antialiased;
|
|
1725
|
+
-moz-osx-font-smoothing: grayscale;
|
|
1726
|
+
font-synthesis: none;
|
|
1727
|
+
text-rendering: optimizeLegibility;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/*
|
|
1731
|
+
* Do not style `input[type=range]` pseudo-elements here. WebKit paints the range control
|
|
1732
|
+
* above sibling divs (`.sliderTrack`, thumb); forcing `-webkit-appearance`/thumb sizing
|
|
1733
|
+
* hid the custom progress fill and card chrome in real apps (Tailwind + host resets).
|
|
1734
|
+
*/
|
|
1735
|
+
|
|
1736
|
+
/* Swatch triggers keep inline `background` / gradients vs global `button { background: none }`. */
|
|
1737
|
+
.aporiaPanel button.gradientSwatchBtn,
|
|
1738
|
+
.aporiaPanel button.colorSwatchBtn {
|
|
1739
|
+
appearance: none;
|
|
1740
|
+
-webkit-appearance: none;
|
|
1741
|
+
margin: 0;
|
|
1742
|
+
box-sizing: border-box;
|
|
1743
|
+
border-style: solid;
|
|
1744
|
+
border-width: 0;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
/*
|
|
1748
|
+
* Select listbox: duplicate Base UI’s selected / highlighted visuals with higher
|
|
1749
|
+
* specificity than generic `[role="option"]` rules from host design systems.
|
|
1750
|
+
*/
|
|
1751
|
+
.selectPopup .selectList > .selectItem[role='option'][data-highlighted] {
|
|
1752
|
+
background-color: #141414 !important;
|
|
1753
|
+
color: #ffffff !important;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
.selectPopup .selectList > .selectItem[role='option'][data-selected]:not([data-highlighted]),
|
|
1757
|
+
.selectPopup .selectList > .selectItem[role='option'][aria-selected='true']:not([data-highlighted]) {
|
|
1758
|
+
background-color: transparent !important;
|
|
1759
|
+
color: #ffffff !important;
|
|
1760
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export { ColorPicker } from './components/ColorPicker';
|
|
|
11
11
|
export type { ColorPickerProps } from './components/ColorPicker';
|
|
12
12
|
export { ToggleRow } from './components/ToggleRow';
|
|
13
13
|
export type { ToggleRowProps } from './components/ToggleRow';
|
|
14
|
+
export { SelectRow } from './components/SelectRow';
|
|
15
|
+
export type { SelectRowProps, SelectRowOption } from './components/SelectRow';
|
|
14
16
|
export { GradientRow } from './components/GradientRow';
|
|
15
17
|
export type { GradientRowProps } from './components/GradientRow';
|
|
16
18
|
export { GradientPicker, stopsToGradient, parseGradient, DEFAULT_GRADIENT_STOPS } from './components/GradientPicker';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,OAAO,aAAa,CAAA;AAGpB,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAE1E,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,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAE7E,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;AAE7D,0FAA0F;AAC1F,OAAO,uBAAuB,CAAA"}
|