@gratiaos/ui 1.0.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.
Files changed (60) hide show
  1. package/LICENSE +243 -0
  2. package/README.md +170 -0
  3. package/dist/hooks/index.d.ts +2 -0
  4. package/dist/hooks/index.d.ts.map +1 -0
  5. package/dist/hooks/index.js +2 -0
  6. package/dist/hooks/index.js.map +1 -0
  7. package/dist/hooks/useMissingScrew.d.ts +40 -0
  8. package/dist/hooks/useMissingScrew.d.ts.map +1 -0
  9. package/dist/hooks/useMissingScrew.js +76 -0
  10. package/dist/hooks/useMissingScrew.js.map +1 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +9 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/pad/Button.d.ts +10 -0
  16. package/dist/pad/Button.d.ts.map +1 -0
  17. package/dist/pad/Button.js +7 -0
  18. package/dist/pad/Button.js.map +1 -0
  19. package/dist/pad/Card.d.ts +8 -0
  20. package/dist/pad/Card.d.ts.map +1 -0
  21. package/dist/pad/Card.js +3 -0
  22. package/dist/pad/Card.js.map +1 -0
  23. package/dist/primitives/badge.d.ts +66 -0
  24. package/dist/primitives/badge.d.ts.map +1 -0
  25. package/dist/primitives/badge.js +23 -0
  26. package/dist/primitives/badge.js.map +1 -0
  27. package/dist/primitives/button.d.ts +60 -0
  28. package/dist/primitives/button.d.ts.map +1 -0
  29. package/dist/primitives/button.js +39 -0
  30. package/dist/primitives/button.js.map +1 -0
  31. package/dist/primitives/card.d.ts +54 -0
  32. package/dist/primitives/card.d.ts.map +1 -0
  33. package/dist/primitives/card.js +11 -0
  34. package/dist/primitives/card.js.map +1 -0
  35. package/dist/primitives/field.d.ts +107 -0
  36. package/dist/primitives/field.d.ts.map +1 -0
  37. package/dist/primitives/field.js +154 -0
  38. package/dist/primitives/field.js.map +1 -0
  39. package/dist/primitives/pill.d.ts +59 -0
  40. package/dist/primitives/pill.d.ts.map +1 -0
  41. package/dist/primitives/pill.js +26 -0
  42. package/dist/primitives/pill.js.map +1 -0
  43. package/dist/primitives/slot.d.ts +7 -0
  44. package/dist/primitives/slot.d.ts.map +1 -0
  45. package/dist/primitives/slot.js +9 -0
  46. package/dist/primitives/slot.js.map +1 -0
  47. package/dist/primitives/toast.d.ts +125 -0
  48. package/dist/primitives/toast.d.ts.map +1 -0
  49. package/dist/primitives/toast.js +462 -0
  50. package/dist/primitives/toast.js.map +1 -0
  51. package/package.json +87 -0
  52. package/styles/badge.css +175 -0
  53. package/styles/base.css +7 -0
  54. package/styles/button.css +257 -0
  55. package/styles/card.css +195 -0
  56. package/styles/field.css +195 -0
  57. package/styles/pad.css +140 -0
  58. package/styles/pill.css +167 -0
  59. package/styles/theme.css +492 -0
  60. package/styles/toast.css +286 -0
@@ -0,0 +1,286 @@
1
+ @layer components {
2
+ /* ─────────────────────────────────────────────────────────────
3
+ Garden UI — Toast skin (headless primitive)
4
+ Whisper: "news should land softly, then move on." 🌬️
5
+
6
+ Purpose
7
+ • Selector-only skin for the headless Toast primitive.
8
+ • Tokens drive all visuals (no hardcoded hex).
9
+ • Calm by default; readable in both light/dark.
10
+
11
+ Data API (from the primitive)
12
+ • [data-ui="toast"] — container
13
+ ◦ [data-position="bottom-center|top-right|top-center|bottom-right"]
14
+ • [data-role="stack"] — internal stack wrapper (grid)
15
+ • [data-ui="toast-item"] — individual toast
16
+ ◦ [data-variant="neutral|positive|warning|danger"]
17
+ ◦ optional [data-state="entering|leaving"] for transitions (future-friendly)
18
+ ◦ children:
19
+ · [data-role="icon"] — optional leading emoji/glyph
20
+ · [data-role="content"] — wrapper for title/desc
21
+ · [data-role="title"] — strong line
22
+ · [data-role="desc"] — secondary line
23
+ · [data-role="message"] — single-line back-compat
24
+
25
+ A11y
26
+ • Items use role="status" + aria-atomic="true" so screen readers announce
27
+ the toast as a single unit. Timers pause on :hover / :focus-visible.
28
+
29
+ Tokens used
30
+ • Surface : --elev / --surface
31
+ • Text : --text / --text-subtle
32
+ • Accent : --color-accent / --color-positive / --color-warning / --color-danger
33
+ • Border : --border
34
+ • Motion : --animate-breathe, --duration-snug, --ease-soft
35
+ • Ring (focus): --ring-color (optional, falls back to accent mix)
36
+
37
+ Notes
38
+ • Keep the HTML minimal; this skin is resilient to the single-line legacy
39
+ form and the newer title+desc content model.
40
+ ──────────────────────────────────────────────────────────── */
41
+
42
+ /* Container positions */
43
+ [data-ui='toast'][data-position='bottom-center'] {
44
+ position: fixed;
45
+ left: 0;
46
+ right: 0;
47
+ bottom: max(16px, env(safe-area-inset-bottom));
48
+ display: flex;
49
+ justify-content: center;
50
+ pointer-events: none;
51
+ z-index: 50;
52
+ }
53
+ [data-ui='toast'][data-position='top-right'] {
54
+ position: fixed;
55
+ right: 16px;
56
+ top: max(16px, env(safe-area-inset-top));
57
+ pointer-events: none;
58
+ z-index: 50;
59
+ }
60
+ [data-ui='toast'][data-position='top-center'] {
61
+ position: fixed;
62
+ left: 0;
63
+ right: 0;
64
+ top: max(16px, env(safe-area-inset-top));
65
+ display: flex;
66
+ justify-content: center;
67
+ pointer-events: none;
68
+ z-index: 50;
69
+ }
70
+ [data-ui='toast'][data-position='bottom-right'] {
71
+ position: fixed;
72
+ right: 16px;
73
+ bottom: max(16px, env(safe-area-inset-bottom));
74
+ pointer-events: none;
75
+ z-index: 50;
76
+ }
77
+
78
+ /* Stack layout */
79
+ [data-ui='toast'] [data-role='stack'] {
80
+ display: grid;
81
+ gap: 8px;
82
+ }
83
+
84
+ /* Stack alignment helpers per position */
85
+ [data-ui='toast'][data-position='top-right'] [data-role='stack'],
86
+ [data-ui='toast'][data-position='bottom-right'] [data-role='stack'] {
87
+ justify-items: end;
88
+ }
89
+ [data-ui='toast'][data-position='bottom-center'] [data-role='stack'],
90
+ [data-ui='toast'][data-position='top-center'] [data-role='stack'] {
91
+ justify-items: center;
92
+ }
93
+
94
+ /* Burst protection — cap stack height & allow smooth scroll on overflow */
95
+ [data-ui='toast'] [data-role='stack'] {
96
+ /* Cap visible height; avoid scroll for normal usage */
97
+ max-height: min(40vh, 50svh);
98
+ overflow-y: auto;
99
+ overscroll-behavior: contain;
100
+ -webkit-overflow-scrolling: touch;
101
+ scroll-behavior: smooth;
102
+ padding-block: 2px; /* tiny cushion for focus ring / last item */
103
+ }
104
+
105
+ /* Tighter caps per position (right stacks typically shorter) */
106
+ [data-ui='toast'][data-position='top-right'] [data-role='stack'],
107
+ [data-ui='toast'][data-position='bottom-right'] [data-role='stack'] {
108
+ max-height: min(36vh, 44svh);
109
+ }
110
+
111
+ /* Subtle scrollbar styling */
112
+ [data-ui='toast'] [data-role='stack']::-webkit-scrollbar {
113
+ width: 8px;
114
+ }
115
+ [data-ui='toast'] [data-role='stack']::-webkit-scrollbar-thumb {
116
+ background: color-mix(in oklab, var(--color-text) 18%, transparent);
117
+ border-radius: 8px;
118
+ }
119
+ [data-ui='toast'] [data-role='stack']::-webkit-scrollbar-thumb:hover {
120
+ background: color-mix(in oklab, var(--color-text) 28%, transparent);
121
+ }
122
+ [data-ui='toast'] [data-role='stack']::-webkit-scrollbar-track {
123
+ background: transparent;
124
+ }
125
+
126
+ /* Firefox */
127
+ [data-ui='toast'] [data-role='stack'] {
128
+ scrollbar-width: thin;
129
+ scrollbar-color: color-mix(in oklab, var(--color-text) 22%, transparent) transparent;
130
+ }
131
+
132
+ /* Item skin */
133
+ [data-ui='toast-item'] {
134
+ pointer-events: auto;
135
+ display: flex;
136
+ align-items: center;
137
+ gap: 10px;
138
+ background: var(--elev);
139
+ color: var(--text);
140
+ border: 1px solid var(--border);
141
+ border-left: 3px solid var(--bar, var(--color-accent));
142
+ border-radius: var(--radius-pill);
143
+ padding: 8px 12px;
144
+ box-shadow: var(--shadow-card-ambient);
145
+ max-width: min(92vw, 520px);
146
+ margin: 0 auto;
147
+ animation: var(--animate-breathe);
148
+ transition: opacity var(--duration-snug) var(--ease-soft), transform var(--duration-snug) var(--ease-soft);
149
+ will-change: opacity, transform;
150
+ cursor: pointer;
151
+ }
152
+
153
+ /* Leading icon (optional) — keeps emoji/glyphs neatly aligned */
154
+ [data-ui='toast-item'] [data-role='icon'] {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ flex: 0 0 auto; /* do not shrink */
159
+ width: 18px;
160
+ height: 18px;
161
+ font-size: 14px; /* emoji size */
162
+ line-height: 1;
163
+ opacity: 0.95;
164
+ }
165
+
166
+ /* Content layout — single line by default; becomes vertical when title/desc present */
167
+ [data-ui='toast-item'] [data-role='content'] {
168
+ display: flex;
169
+ flex-direction: column;
170
+ align-items: flex-start;
171
+ gap: 2px;
172
+ min-width: 0; /* allow text wrap */
173
+ }
174
+
175
+ /* Typography */
176
+ [data-ui='toast-item'] [data-role='title'] {
177
+ font-size: 14px;
178
+ font-weight: 600;
179
+ line-height: 1.2;
180
+ color: var(--text);
181
+ }
182
+ [data-ui='toast-item'] [data-role='desc'],
183
+ [data-ui='toast-item'] [data-role='message'] {
184
+ font-size: 13px;
185
+ line-height: 1.25;
186
+ color: var(--text-subtle);
187
+ }
188
+
189
+ /* Clamp long descriptions to ~3 lines */
190
+ [data-ui='toast-item'] [data-role='desc'] {
191
+ display: -webkit-box;
192
+ -webkit-line-clamp: 3;
193
+ -webkit-box-orient: vertical;
194
+ overflow: hidden;
195
+ word-break: break-word;
196
+ }
197
+
198
+ /* Single-line message with ellipsis */
199
+ [data-ui='toast-item'] [data-role='message'] {
200
+ white-space: nowrap;
201
+ overflow: hidden;
202
+ text-overflow: ellipsis;
203
+ }
204
+
205
+ /* Back-compat: when only [data-role='message'] exists (no content wrapper) */
206
+ [data-ui='toast-item'] > [data-role='message'] {
207
+ font-size: 14px;
208
+ color: var(--text);
209
+ white-space: nowrap;
210
+ overflow: hidden;
211
+ text-overflow: ellipsis;
212
+ }
213
+
214
+ /* Variants set the accent bar color */
215
+ [data-ui='toast-item'][data-variant='neutral'] {
216
+ --bar: var(--color-accent);
217
+ }
218
+ [data-ui='toast-item'][data-variant='positive'] {
219
+ --bar: var(--color-positive);
220
+ }
221
+ [data-ui='toast-item'][data-variant='warning'] {
222
+ --bar: var(--color-warning);
223
+ }
224
+ [data-ui='toast-item'][data-variant='danger'] {
225
+ --bar: var(--color-danger);
226
+ }
227
+ /* Alias — info maps to accent (DX sugar) */
228
+ [data-ui='toast-item'][data-variant='info'] {
229
+ --bar: var(--color-accent);
230
+ }
231
+
232
+ /* Transient state — gentle entrance */
233
+ [data-ui='toast-item'][data-state='entering'] {
234
+ opacity: 0;
235
+ transform: translateY(-4px) scale(0.98);
236
+ /* The base rule already defines transition; we just set the starting pose.
237
+ When JS removes [data-state='entering'], it eases to opacity:1 / transform:none. */
238
+ }
239
+
240
+ /* Transient state — graceful exit */
241
+ [data-ui='toast-item'][data-state='leaving'] {
242
+ opacity: 0;
243
+ transform: translateY(4px) scale(0.98);
244
+ transition: opacity var(--duration-snug) var(--ease-soft), transform var(--duration-snug) var(--ease-soft);
245
+ pointer-events: none; /* avoid clicks while fading */
246
+ }
247
+
248
+ /* Position-aware vectors — slide down from top, up from bottom */
249
+ [data-ui='toast'][data-position='top-right'] [data-ui='toast-item'][data-state='entering'],
250
+ [data-ui='toast'][data-position='top-center'] [data-ui='toast-item'][data-state='entering'] {
251
+ transform: translateY(-6px) scale(0.98);
252
+ }
253
+ [data-ui='toast'][data-position='top-right'] [data-ui='toast-item'][data-state='leaving'],
254
+ [data-ui='toast'][data-position='top-center'] [data-ui='toast-item'][data-state='leaving'] {
255
+ transform: translateY(-6px) scale(0.98);
256
+ }
257
+
258
+ [data-ui='toast'][data-position='bottom-right'] [data-ui='toast-item'][data-state='entering'],
259
+ [data-ui='toast'][data-position='bottom-center'] [data-ui='toast-item'][data-state='entering'] {
260
+ transform: translateY(6px) scale(0.98);
261
+ }
262
+ [data-ui='toast'][data-position='bottom-right'] [data-ui='toast-item'][data-state='leaving'],
263
+ [data-ui='toast'][data-position='bottom-center'] [data-ui='toast-item'][data-state='leaving'] {
264
+ transform: translateY(6px) scale(0.98);
265
+ }
266
+
267
+ /* Focus visibility — match ring semantics used across primitives */
268
+ [data-ui='toast-item']:focus-visible {
269
+ outline: 2px solid var(--ring-color, color-mix(in oklab, var(--color-accent) 60%, transparent));
270
+ outline-offset: 2px;
271
+ }
272
+
273
+ /* Motion accessibility */
274
+ @media (prefers-reduced-motion: reduce) {
275
+ [data-ui='toast-item'] {
276
+ animation: none;
277
+ }
278
+ [data-ui='toast-item'][data-state='leaving'] {
279
+ transform: none;
280
+ transition: opacity var(--duration-snug) var(--ease-soft);
281
+ }
282
+ [data-ui='toast-item'][data-state='entering'] {
283
+ transform: none;
284
+ }
285
+ }
286
+ }