@enigmax/primitives 0.21.0 → 0.23.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/dist/chunk-3BQVOOAM.js +388 -0
- package/dist/{chunk-QQFNAKMY.js → chunk-45UHLZYT.js} +1 -1
- package/dist/chunk-4VUHQFAT.js +130 -0
- package/dist/{chunk-D5A2ZMAG.js → chunk-4ZPMP47J.js} +6 -1
- package/dist/chunk-DSBYVA7V.js +713 -0
- package/dist/{chunk-FWVWX67R.js → chunk-FGBIZDV2.js} +3 -3
- package/dist/{chunk-R4ZAEE7V.js → chunk-KEVZ5XQV.js} +1 -1
- package/dist/chunk-N6PDHMAX.js +213 -0
- package/dist/chunk-NONGREXC.js +248 -0
- package/dist/chunk-VKL3DEIQ.js +804 -0
- package/dist/chunk-WPTBURIC.js +1627 -0
- package/dist/chunk-WSQC3PCC.js +466 -0
- package/dist/context-menu-D3FtTn7v.d.ts +174 -0
- package/dist/{index-dTdAbOWl.d.ts → index-DQNnohoo.d.ts} +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +8 -4
- package/dist/keys-D2zJs1uB.d.ts +100 -0
- package/dist/next/index.d.ts +12 -5
- package/dist/next/index.js +21 -14
- package/dist/react/button.d.ts +2 -2
- package/dist/react/context-menu.d.ts +202 -0
- package/dist/react/context-menu.js +6 -0
- package/dist/react/index.d.ts +11 -4
- package/dist/react/index.js +20 -13
- package/dist/react/input.d.ts +2 -2
- package/dist/react/input.js +1 -1
- package/dist/react/palette.d.ts +1 -1
- package/dist/react/palette.js +3 -3
- package/dist/react/search.d.ts +1 -1
- package/dist/react/search.js +2 -2
- package/dist/react/select.d.ts +217 -0
- package/dist/react/select.js +7 -0
- package/dist/react/selection.d.ts +104 -0
- package/dist/react/selection.js +4 -0
- package/dist/react/slot.d.ts +2 -2
- package/dist/react/toast.d.ts +165 -32
- package/dist/react/toast.js +1 -1
- package/dist/react-router/index.d.ts +12 -5
- package/dist/react-router/index.js +21 -14
- package/dist/search/index.d.ts +2 -2
- package/dist/search/index.js +1 -1
- package/dist/{search-DXxY8SEH.d.ts → search-DYgqRp37.d.ts} +20 -3
- package/dist/{search-UQEXAPQB.js → search-PBZORZ7P.js} +1 -1
- package/dist/select-ClSy-J1f.d.ts +100 -0
- package/dist/selection-B_pmzHpy.d.ts +150 -0
- package/package.json +21 -2
- package/recipes/context-menu/styles.css +177 -0
- package/recipes/input/styles.css +9 -0
- package/recipes/palette/styles.css +3 -0
- package/recipes/search/tailwind.tsx +3 -2
- package/recipes/select/styles.css +230 -0
- package/recipes/toast/styles.css +688 -192
- package/registry.json +434 -29
- package/src/core/context-menu.ts +694 -0
- package/src/core/keys.ts +264 -0
- package/src/core/search.ts +25 -1
- package/src/core/select.ts +404 -0
- package/src/core/selection.ts +648 -0
- package/src/index.ts +60 -1
- package/src/react/context-menu/context.ts +57 -0
- package/src/react/context-menu/index.tsx +94 -0
- package/src/react/context-menu/root.tsx +846 -0
- package/src/react/context-menu/styles.ts +186 -0
- package/src/react/index.ts +70 -2
- package/src/react/palette/root.tsx +2 -2
- package/src/react/select/context.ts +56 -0
- package/src/react/select/index.tsx +96 -0
- package/src/react/select/root.tsx +839 -0
- package/src/react/select/styles.ts +238 -0
- package/src/react/selection/index.tsx +115 -0
- package/src/react/selection/use-selection.ts +260 -0
- package/src/react/toast/NOTICE +20 -0
- package/src/react/toast/assets.tsx +85 -0
- package/src/react/toast/cn.ts +10 -0
- package/src/react/toast/hooks.ts +13 -0
- package/src/react/toast/index.tsx +736 -0
- package/src/react/toast/state.ts +207 -0
- package/src/react/toast/styles.ts +738 -0
- package/src/react/toast/types.ts +193 -0
- package/src/react/toaster.tsx +76 -341
- package/dist/chunk-JCCL7XKC.js +0 -465
- package/src/react/toast-styles.ts +0 -247
- /package/dist/{chunk-U3V4EHOB.js → chunk-3HDEZ2E7.js} +0 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The select stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* GENERATED from src/react/select/styles.ts by scripts/sync-recipes.mjs - edit that file, not
|
|
5
|
+
* this one. It exists as a stylesheet as well as a string because the component injects it,
|
|
6
|
+
* and this is the same sheet for anyone who would rather import it, copy it with
|
|
7
|
+
* `enigma add select --copy`, or fork it outright.
|
|
8
|
+
*/
|
|
9
|
+
:root {
|
|
10
|
+
--enigma-select-bg: #171717;
|
|
11
|
+
--enigma-select-border: #404040;
|
|
12
|
+
--enigma-select-border-focus: #a3a3a3;
|
|
13
|
+
--enigma-select-text: #f5f5f5;
|
|
14
|
+
--enigma-select-muted: #a3a3a3;
|
|
15
|
+
--enigma-select-radius: 0.5rem;
|
|
16
|
+
--enigma-select-font-size: 0.875rem;
|
|
17
|
+
--enigma-select-padding: 0.5rem 0.75rem;
|
|
18
|
+
|
|
19
|
+
--enigma-select-panel-bg: #1c1c1c;
|
|
20
|
+
--enigma-select-panel-border: #333333;
|
|
21
|
+
--enigma-select-panel-radius: 0.625rem;
|
|
22
|
+
--enigma-select-panel-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
|
|
23
|
+
--enigma-select-panel-width: 100%;
|
|
24
|
+
--enigma-select-list-height: 15rem;
|
|
25
|
+
|
|
26
|
+
--enigma-select-active-bg: #2a2a2a;
|
|
27
|
+
--enigma-select-accent: #fbbf24;
|
|
28
|
+
--enigma-select-tag-bg: #2a2a2a;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@media (prefers-color-scheme: light) {
|
|
32
|
+
:root {
|
|
33
|
+
--enigma-select-bg: #ffffff;
|
|
34
|
+
--enigma-select-border: #d4d4d4;
|
|
35
|
+
--enigma-select-border-focus: #737373;
|
|
36
|
+
--enigma-select-text: #171717;
|
|
37
|
+
--enigma-select-muted: #737373;
|
|
38
|
+
--enigma-select-panel-bg: #ffffff;
|
|
39
|
+
--enigma-select-panel-border: #e5e5e5;
|
|
40
|
+
--enigma-select-panel-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
|
|
41
|
+
--enigma-select-active-bg: #f5f5f5;
|
|
42
|
+
--enigma-select-accent: #b45309;
|
|
43
|
+
--enigma-select-tag-bg: #f0f0f0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[data-enigma-select-root] { position: relative; display: inline-block; min-width: 0; }
|
|
48
|
+
|
|
49
|
+
[data-enigma-select-trigger] {
|
|
50
|
+
display: flex; align-items: center; gap: 0.5rem;
|
|
51
|
+
width: 100%; min-width: 0; box-sizing: border-box;
|
|
52
|
+
padding: var(--enigma-select-padding);
|
|
53
|
+
font: inherit; font-size: var(--enigma-select-font-size); text-align: left;
|
|
54
|
+
color: var(--enigma-select-text); background: var(--enigma-select-bg);
|
|
55
|
+
border: 1px solid var(--enigma-select-border); border-radius: var(--enigma-select-radius);
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
}
|
|
58
|
+
[data-enigma-select-trigger]:focus-visible { outline: 2px solid var(--enigma-select-border-focus); outline-offset: 1px; }
|
|
59
|
+
[data-enigma-select-trigger][data-open] { border-color: var(--enigma-select-border-focus); }
|
|
60
|
+
[data-enigma-select-trigger]:disabled,
|
|
61
|
+
[data-enigma-select-trigger][aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
|
|
62
|
+
/* Nothing to choose, or nothing yet: the control reads as unavailable and the caret fades,
|
|
63
|
+
because a caret at full strength promises a panel that will never open. Not the disabled
|
|
64
|
+
look, which would say the field is off rather than that the list is empty. */
|
|
65
|
+
[data-enigma-select-trigger][data-empty],
|
|
66
|
+
[data-enigma-select-trigger][data-loading] { opacity: 1; cursor: default; }
|
|
67
|
+
[data-enigma-select-trigger][data-empty] [data-enigma-select-caret],
|
|
68
|
+
[data-enigma-select-trigger][data-loading] [data-enigma-select-caret] { opacity: 0.25; }
|
|
69
|
+
|
|
70
|
+
/* The indicator: one slot, holding the caret and the × stacked in the same cell. Side by
|
|
71
|
+
side they would be two targets a pixel apart - one of which throws away your choice - and
|
|
72
|
+
the pair would change the trigger's width the moment a value appeared. */
|
|
73
|
+
[data-enigma-select-indicator] {
|
|
74
|
+
display: grid; place-items: center; flex: none;
|
|
75
|
+
margin-left: auto; width: 1rem; height: 1rem;
|
|
76
|
+
}
|
|
77
|
+
[data-enigma-select-indicator] > * { grid-area: 1 / 1; }
|
|
78
|
+
|
|
79
|
+
/* The caret, drawn rather than loaded: an icon font or an SVG file is a request, and this
|
|
80
|
+
is two borders. */
|
|
81
|
+
[data-enigma-select-caret] {
|
|
82
|
+
width: 0.4rem; height: 0.4rem;
|
|
83
|
+
/* Decoration, and it must not be the hit target: the rotation gives it a stacking
|
|
84
|
+
context, which paints it OVER the × sharing its cell and swallows the click. */
|
|
85
|
+
pointer-events: none;
|
|
86
|
+
border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
|
|
87
|
+
transform: translateY(-0.1rem) rotate(45deg);
|
|
88
|
+
opacity: 0.6; transition: transform 120ms ease-out, opacity 120ms ease-out;
|
|
89
|
+
}
|
|
90
|
+
[data-enigma-select-trigger][data-open] [data-enigma-select-caret] { transform: translateY(0.1rem) rotate(225deg); }
|
|
91
|
+
|
|
92
|
+
[data-enigma-select-value] {
|
|
93
|
+
display: flex; align-items: center; gap: 0.375rem;
|
|
94
|
+
/* min-width: 0 is what lets the ellipsis happen: a flex item's default minimum is its
|
|
95
|
+
content, so without it a long label pushes the caret out of the button. */
|
|
96
|
+
min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
97
|
+
}
|
|
98
|
+
[data-enigma-select-value][data-placeholder] { color: var(--enigma-select-muted); }
|
|
99
|
+
[data-enigma-select-value][data-tags] { flex-wrap: wrap; white-space: normal; }
|
|
100
|
+
|
|
101
|
+
[data-enigma-select-tag] {
|
|
102
|
+
display: inline-flex; align-items: center; gap: 0.25rem;
|
|
103
|
+
padding: 0.125rem 0.25rem 0.125rem 0.5rem;
|
|
104
|
+
font-size: 0.8125rem; line-height: 1.4;
|
|
105
|
+
background: var(--enigma-select-tag-bg); border-radius: 999px;
|
|
106
|
+
}
|
|
107
|
+
[data-enigma-select-tag][data-rest] { padding: 0.125rem 0.5rem; color: var(--enigma-select-muted); }
|
|
108
|
+
|
|
109
|
+
[data-enigma-select-tag-remove] {
|
|
110
|
+
display: grid; place-items: center;
|
|
111
|
+
width: 1rem; height: 1rem; border-radius: 999px;
|
|
112
|
+
color: var(--enigma-select-muted); font-size: 0.875rem; line-height: 1; cursor: pointer;
|
|
113
|
+
}
|
|
114
|
+
[data-enigma-select-tag-remove]:hover { color: var(--enigma-select-text); background: var(--enigma-select-active-bg); }
|
|
115
|
+
|
|
116
|
+
/* The ×, in the caret's place and only while the control is under the pointer or holds
|
|
117
|
+
focus. ":focus" and not ":focus-visible": a tap focuses the button, and on a touch screen
|
|
118
|
+
there is no hover to reveal it with. */
|
|
119
|
+
[data-enigma-select-clear] {
|
|
120
|
+
display: grid; place-items: center;
|
|
121
|
+
width: 1rem; height: 1rem; border-radius: 999px;
|
|
122
|
+
color: var(--enigma-select-muted); font-size: 0.875rem; line-height: 1; cursor: pointer;
|
|
123
|
+
opacity: 0; pointer-events: none; transition: opacity 120ms ease-out;
|
|
124
|
+
}
|
|
125
|
+
[data-enigma-select-trigger]:hover [data-enigma-select-clear],
|
|
126
|
+
[data-enigma-select-trigger]:focus [data-enigma-select-clear] { opacity: 1; pointer-events: auto; }
|
|
127
|
+
/* Scoped to a trigger that HAS a × - otherwise hovering a select with nothing to clear
|
|
128
|
+
would hide its caret and leave an empty slot. */
|
|
129
|
+
[data-enigma-select-trigger][data-clearable]:hover [data-enigma-select-caret],
|
|
130
|
+
[data-enigma-select-trigger][data-clearable]:focus [data-enigma-select-caret] { opacity: 0; }
|
|
131
|
+
[data-enigma-select-clear]:hover { color: var(--enigma-select-text); background: var(--enigma-select-active-bg); }
|
|
132
|
+
|
|
133
|
+
[data-enigma-select-content] {
|
|
134
|
+
position: absolute; z-index: 50;
|
|
135
|
+
top: calc(100% + 0.25rem); left: 0;
|
|
136
|
+
min-width: var(--enigma-select-panel-width); box-sizing: border-box;
|
|
137
|
+
padding: 0.25rem;
|
|
138
|
+
background: var(--enigma-select-panel-bg);
|
|
139
|
+
border: 1px solid var(--enigma-select-panel-border);
|
|
140
|
+
border-radius: var(--enigma-select-panel-radius);
|
|
141
|
+
box-shadow: var(--enigma-select-panel-shadow);
|
|
142
|
+
animation: enigma-select-in 120ms ease-out;
|
|
143
|
+
/* A bound, because the content is arbitrary: a long option label or a query typed into
|
|
144
|
+
the filter would otherwise widen the panel with it. min-width still wins for a
|
|
145
|
+
trigger wider than this, which is what it is for. */
|
|
146
|
+
max-width: min(28rem, calc(100vw - 2rem));
|
|
147
|
+
}
|
|
148
|
+
/* Opening upwards is not a variant, it is the same panel measured against the window: near
|
|
149
|
+
the bottom of the screen the list would otherwise be unreachable. */
|
|
150
|
+
[data-enigma-select-content][data-side="top"] { top: auto; bottom: calc(100% + 0.25rem); }
|
|
151
|
+
[data-enigma-select-content][data-state="closed"] { animation: enigma-select-out 120ms ease-in forwards; pointer-events: none; }
|
|
152
|
+
|
|
153
|
+
@keyframes enigma-select-in {
|
|
154
|
+
from { opacity: 0; transform: translateY(-0.25rem); }
|
|
155
|
+
to { opacity: 1; transform: none; }
|
|
156
|
+
}
|
|
157
|
+
@keyframes enigma-select-out {
|
|
158
|
+
from { opacity: 1; }
|
|
159
|
+
to { opacity: 0; transform: translateY(-0.125rem); }
|
|
160
|
+
}
|
|
161
|
+
@media (prefers-reduced-motion: reduce) {
|
|
162
|
+
[data-enigma-select-content],
|
|
163
|
+
[data-enigma-select-content][data-state="closed"] { animation: none; }
|
|
164
|
+
[data-enigma-select-trigger]::after { transition: none; }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
[data-enigma-select-search] {
|
|
168
|
+
width: 100%; box-sizing: border-box;
|
|
169
|
+
padding: 0.375rem 0.5rem 0.5rem;
|
|
170
|
+
font: inherit; font-size: var(--enigma-select-font-size);
|
|
171
|
+
color: var(--enigma-select-text); background: transparent;
|
|
172
|
+
border: 0; border-bottom: 1px solid var(--enigma-select-panel-border);
|
|
173
|
+
outline: none;
|
|
174
|
+
}
|
|
175
|
+
/* WebKit's own clear cross, gone: it is drawn on no other engine, so leaving it in gives
|
|
176
|
+
half the visitors a control the other half never sees. */
|
|
177
|
+
[data-enigma-select-search]::-webkit-search-cancel-button,
|
|
178
|
+
[data-enigma-select-search]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
|
|
179
|
+
|
|
180
|
+
[data-enigma-select-list] {
|
|
181
|
+
max-height: var(--enigma-select-list-height);
|
|
182
|
+
margin-top: 0.25rem;
|
|
183
|
+
overflow-y: auto; overscroll-behavior: contain;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
[data-enigma-select-group-label] {
|
|
187
|
+
margin: 0.375rem 0 0.125rem; padding: 0 0.5rem;
|
|
188
|
+
font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;
|
|
189
|
+
color: var(--enigma-select-muted);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
[data-enigma-select-option] {
|
|
193
|
+
display: flex; align-items: center; gap: 0.5rem;
|
|
194
|
+
padding: 0.4375rem 0.5rem; border-radius: 0.375rem;
|
|
195
|
+
font-size: var(--enigma-select-font-size); color: var(--enigma-select-text);
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
}
|
|
198
|
+
[data-enigma-select-option][data-active] { background: var(--enigma-select-active-bg); }
|
|
199
|
+
[data-enigma-select-option][data-disabled] { opacity: 0.45; cursor: not-allowed; }
|
|
200
|
+
|
|
201
|
+
[data-enigma-select-option-text] { display: grid; min-width: 0; }
|
|
202
|
+
[data-enigma-select-option-label] { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
203
|
+
[data-enigma-select-option-description] {
|
|
204
|
+
font-size: 0.75rem; color: var(--enigma-select-muted);
|
|
205
|
+
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
[data-enigma-select-icon] { display: inline-flex; align-items: center; flex: none; max-height: 1.25em; line-height: 0; }
|
|
209
|
+
|
|
210
|
+
/* The check, drawn with two borders and shown only where it belongs. Reserved space either
|
|
211
|
+
way, so choosing a row does not shift the label under the pointer. */
|
|
212
|
+
[data-enigma-select-check] {
|
|
213
|
+
flex: none; margin-left: auto;
|
|
214
|
+
width: 0.35rem; height: 0.6rem;
|
|
215
|
+
border-right: 2px solid var(--enigma-select-accent); border-bottom: 2px solid var(--enigma-select-accent);
|
|
216
|
+
transform: rotate(45deg) translate(-0.05rem, -0.05rem);
|
|
217
|
+
opacity: 0;
|
|
218
|
+
}
|
|
219
|
+
[data-enigma-select-option][data-selected] [data-enigma-select-check] { opacity: 1; }
|
|
220
|
+
|
|
221
|
+
/* The end-of-window marker: one pixel, so it has a box to be scrolled into. */
|
|
222
|
+
[data-enigma-select-more] { height: 1px; }
|
|
223
|
+
|
|
224
|
+
[data-enigma-select-empty] {
|
|
225
|
+
margin: 0; padding: 0.75rem 0.5rem;
|
|
226
|
+
font-size: var(--enigma-select-font-size); color: var(--enigma-select-muted);
|
|
227
|
+
/* The quoted query is cut in the text as well, but a pasted string with no spaces has
|
|
228
|
+
no break opportunity at all - so this is what stops it stretching the panel. */
|
|
229
|
+
overflow-wrap: anywhere;
|
|
230
|
+
}
|