@civitai/blocks-react 0.46.0 → 0.48.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 (51) hide show
  1. package/README.md +65 -3
  2. package/dist/hooks/useCollectionFollow.d.ts +141 -0
  3. package/dist/hooks/useCollectionFollow.d.ts.map +1 -0
  4. package/dist/hooks/useCollectionFollow.js +202 -0
  5. package/dist/hooks/useCollectionFollow.js.map +1 -0
  6. package/dist/index.d.ts +4 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +5 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal/iframeTransport.d.ts.map +1 -1
  11. package/dist/internal/iframeTransport.js +5 -2
  12. package/dist/internal/iframeTransport.js.map +1 -1
  13. package/dist/internal/liveHost.d.ts.map +1 -1
  14. package/dist/internal/liveHost.js +33 -0
  15. package/dist/internal/liveHost.js.map +1 -1
  16. package/dist/internal/mockHost.d.ts +17 -2
  17. package/dist/internal/mockHost.d.ts.map +1 -1
  18. package/dist/internal/mockHost.js +49 -0
  19. package/dist/internal/mockHost.js.map +1 -1
  20. package/dist/internal/requestTimeouts.d.ts.map +1 -1
  21. package/dist/internal/requestTimeouts.js +8 -0
  22. package/dist/internal/requestTimeouts.js.map +1 -1
  23. package/dist/internal/transport.d.ts +19 -0
  24. package/dist/internal/transport.d.ts.map +1 -1
  25. package/dist/internal/transport.js +24 -0
  26. package/dist/internal/transport.js.map +1 -1
  27. package/dist/internal/validate.d.ts +20 -0
  28. package/dist/internal/validate.d.ts.map +1 -1
  29. package/dist/internal/validate.js +43 -0
  30. package/dist/internal/validate.js.map +1 -1
  31. package/dist/ui/FollowButton.d.ts +85 -0
  32. package/dist/ui/FollowButton.d.ts.map +1 -0
  33. package/dist/ui/FollowButton.js +162 -0
  34. package/dist/ui/FollowButton.js.map +1 -0
  35. package/dist/ui/ResourceCard.d.ts +272 -0
  36. package/dist/ui/ResourceCard.d.ts.map +1 -0
  37. package/dist/ui/ResourceCard.js +243 -0
  38. package/dist/ui/ResourceCard.js.map +1 -0
  39. package/dist/ui/TipButton.d.ts +115 -0
  40. package/dist/ui/TipButton.d.ts.map +1 -0
  41. package/dist/ui/TipButton.js +308 -0
  42. package/dist/ui/TipButton.js.map +1 -0
  43. package/dist/ui/index.d.ts +6 -0
  44. package/dist/ui/index.d.ts.map +1 -1
  45. package/dist/ui/index.js +3 -0
  46. package/dist/ui/index.js.map +1 -1
  47. package/dist/ui/styles.d.ts +1 -1
  48. package/dist/ui/styles.d.ts.map +1 -1
  49. package/dist/ui/styles.js +202 -7
  50. package/dist/ui/styles.js.map +1 -1
  51. package/package.json +4 -4
package/dist/ui/styles.js CHANGED
@@ -20,10 +20,11 @@ import { tokensCss } from '@civitai/theme';
20
20
  * presentational components (Button, TextInput, Textarea, NumberInput,
21
21
  * Card, Stack, Group, Alert, Loader, Badge), wrapped in
22
22
  * `@layer civitai.components`.
23
- * Only the 5 INTERACTIVE components that live entirely in this package
24
- * (Modal, Select, Slider, Collapse, SegmentedControl) keep their CSS here,
25
- * repointed onto the `--civitai-*` tokens. This is a VISIBLE repaint — the
26
- * design-system tokens differ from the pack's retired `--ci-*` palette
23
+ * Only the components that live entirely in this package keep their CSS here,
24
+ * repointed onto the `--civitai-*` tokens: the original interactive-5
25
+ * (Modal, Select, Slider, Collapse, SegmentedControl) plus ResourceCard,
26
+ * which has no `@civitai/components` counterpart. This is a VISIBLE repaint —
27
+ * the design-system tokens differ from the pack's retired `--ci-*` palette
27
28
  * (radius 8px→4px, teal success, dark primary `#1971C2`, etc.).
28
29
  *
29
30
  * `injectBlocksStyles()` injects THREE `<style>` elements, each with its own
@@ -42,9 +43,14 @@ import { tokensCss } from '@civitai/theme';
42
43
  /** Marker attribute on the injected interactive-5 `<style>` so injection is idempotent. */
43
44
  const STYLE_MARKER = 'data-civitai-blocks-ui';
44
45
  /**
45
- * Interactive-5 component CSS — the styles that live ONLY in this package
46
- * (Modal / Select / Slider / Collapse / SegmentedControl). Repointed onto the
47
- * `--civitai-*` tokens supplied by `@civitai/theme`.
46
+ * Package-local component CSS — the styles that live ONLY in this package
47
+ * (Modal / Select / Slider / Collapse / SegmentedControl, plus ResourceCard).
48
+ * Repointed onto the `--civitai-*` tokens supplied by `@civitai/theme`.
49
+ *
50
+ * (The name `INTERACTIVE_STYLES` and the `interactive-5` label elsewhere are
51
+ * historical: ResourceCard is only sometimes interactive, and joined the block
52
+ * because `@civitai/components` has no counterpart for it, not because it is a
53
+ * sixth control.)
48
54
  *
49
55
  * These rules are intentionally UNLAYERED (unlike @civitai/components' rules,
50
56
  * which live in `@layer civitai.components`). Their selectors are DISJOINT from
@@ -179,6 +185,195 @@ const INTERACTIVE_STYLES = `
179
185
  padding-top: 4px;
180
186
  }
181
187
 
188
+ /* ----- ResourceCard -----
189
+ Two variants off ONE box. data-variant='card' stacks (grid tile),
190
+ data-variant='row' runs inline (compact list line). Every selector is
191
+ double-qualified with [data-civitai-ui='resource-card'] on purpose:
192
+ data-variant is also emitted by Button and Badge, so a bare
193
+ [data-variant='card'] would reach across the whole pack.
194
+ NOTE: this block lives inside a JS TEMPLATE LITERAL. No backticks, and no
195
+ dollar-brace, or the string ends here and the file stops parsing as
196
+ TypeScript (backticks in this comment did exactly that once). */
197
+ [data-civitai-ui='resource-card'] {
198
+ display: flex;
199
+ box-sizing: border-box;
200
+ /* The positioned ancestor for the overlay slot. It lives on the ROOT, not on
201
+ the thumbnail frame, so the overlay can be a SIBLING of the hit <button>
202
+ rather than a descendant of it — see the overlay prop's doc for why that
203
+ distinction is the whole point of the slot. */
204
+ position: relative;
205
+ font-family: var(--civitai-font);
206
+ color: var(--civitai-color-text);
207
+ background: var(--civitai-color-surface);
208
+ border: 1px solid var(--civitai-color-border);
209
+ border-radius: var(--civitai-radius);
210
+ overflow: hidden;
211
+ }
212
+ [data-civitai-ui='resource-card'][data-variant='card'] {
213
+ flex-direction: column;
214
+ align-items: stretch;
215
+ }
216
+ [data-civitai-ui='resource-card'][data-variant='row'] {
217
+ flex-direction: row;
218
+ align-items: center;
219
+ gap: 8px;
220
+ padding: 6px 8px;
221
+ }
222
+ [data-civitai-ui='resource-card'][data-selected='true'] {
223
+ border-color: var(--civitai-color-primary);
224
+ }
225
+ [data-civitai-ui='resource-card'][data-disabled='true'] {
226
+ opacity: 0.6;
227
+ }
228
+ /* The hit area. A <button> when interactive, a <div> when not — both are reset
229
+ to the same box so the two variants lay out identically either way. */
230
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-hit] {
231
+ display: flex;
232
+ /* 🔴 A flex ITEM defaults to min-width:auto, which refuses to shrink below its
233
+ content — so without this the name's nowrap+ellipsis never engages and a
234
+ long model name blows the card out of its grid cell instead of truncating. */
235
+ min-width: 0;
236
+ box-sizing: border-box;
237
+ margin: 0;
238
+ border: none;
239
+ background: transparent;
240
+ color: inherit;
241
+ font: inherit;
242
+ text-align: left;
243
+ }
244
+ [data-civitai-ui='resource-card'][data-variant='card'] [data-civitai-ui-resource-hit] {
245
+ flex-direction: column;
246
+ align-items: stretch;
247
+ gap: 6px;
248
+ padding: 6px;
249
+ }
250
+ [data-civitai-ui='resource-card'][data-variant='row'] [data-civitai-ui-resource-hit] {
251
+ flex: 1 1 auto;
252
+ flex-direction: row;
253
+ align-items: center;
254
+ gap: 8px;
255
+ padding: 0;
256
+ }
257
+ [data-civitai-ui='resource-card'] button[data-civitai-ui-resource-hit] {
258
+ cursor: pointer;
259
+ }
260
+ [data-civitai-ui='resource-card'] button[data-civitai-ui-resource-hit]:disabled {
261
+ cursor: not-allowed;
262
+ }
263
+ [data-civitai-ui='resource-card'] button[data-civitai-ui-resource-hit]:focus-visible {
264
+ outline: 2px solid var(--civitai-color-primary);
265
+ outline-offset: -2px;
266
+ }
267
+ /* The thumbnail frame. Rendered whether or not there is an image — see the
268
+ component's thumbnailUrl doc: BlockResourceInfo has no image field, so "no
269
+ image" is the COMMON case and the frame must keep its box regardless. */
270
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-thumb] {
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: center;
274
+ flex: none;
275
+ overflow: hidden;
276
+ background: var(--civitai-color-surface-2);
277
+ border-radius: calc(var(--civitai-radius) - 1px);
278
+ color: var(--civitai-color-text-dimmed);
279
+ }
280
+ [data-civitai-ui='resource-card'][data-variant='card'] [data-civitai-ui-resource-thumb] {
281
+ /* 🔴 aspect-ratio, not a fixed height: the tile is grid-sized by the caller,
282
+ and this is the line that stops a thumbnail-less card collapsing to a
283
+ text-height sliver. */
284
+ width: 100%;
285
+ aspect-ratio: 1 / 1;
286
+ font-size: 11px;
287
+ }
288
+ [data-civitai-ui='resource-card'][data-variant='row'] [data-civitai-ui-resource-thumb] {
289
+ width: 36px;
290
+ height: 36px;
291
+ font-size: 9px;
292
+ }
293
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-thumb] img {
294
+ width: 100%;
295
+ height: 100%;
296
+ object-fit: cover;
297
+ display: block;
298
+ }
299
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-placeholder] {
300
+ padding: 0 4px;
301
+ text-align: center;
302
+ line-height: 1.2;
303
+ }
304
+ /* Positioned from the ROOT, over the thumbnail corner. 10px = the hit area's
305
+ 6px padding plus a 4px inset inside the frame; the three move together, and
306
+ the browser tier asserts the result lands inside the frame's own rect rather
307
+ than trusting the arithmetic.
308
+ pointer-events: none is load-bearing, not polish: this slot is STATUS, and a
309
+ pill that can swallow a click meant for the card is the same class of bug as
310
+ nesting a control inside the hit <button>. A consumer who really wants an
311
+ interactive badge opts back in with pointer-events: auto on their own node. */
312
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-overlay] {
313
+ position: absolute;
314
+ top: 10px;
315
+ right: 10px;
316
+ z-index: 1;
317
+ pointer-events: none;
318
+ display: flex;
319
+ align-items: center;
320
+ gap: 4px;
321
+ max-width: calc(100% - 20px);
322
+ font-size: 11px;
323
+ line-height: 1;
324
+ }
325
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-nameline] {
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 4px;
329
+ min-width: 0;
330
+ }
331
+ /* The non-colour half of the selected affordance (WCAG 1.4.1). The border-hue
332
+ change on the root is reinforcement; this glyph is what carries it. */
333
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-selected] {
334
+ flex: none;
335
+ font-size: 12px;
336
+ font-weight: 700;
337
+ line-height: 1;
338
+ color: var(--civitai-color-primary);
339
+ }
340
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-text] {
341
+ display: flex;
342
+ flex-direction: column;
343
+ gap: 2px;
344
+ min-width: 0;
345
+ flex: 1 1 auto;
346
+ }
347
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-name] {
348
+ display: block;
349
+ font-size: 13px;
350
+ font-weight: 600;
351
+ line-height: 1.3;
352
+ flex: 1 1 auto;
353
+ min-width: 0;
354
+ overflow: hidden;
355
+ text-overflow: ellipsis;
356
+ white-space: nowrap;
357
+ }
358
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-meta] {
359
+ display: flex;
360
+ flex-wrap: wrap;
361
+ align-items: center;
362
+ gap: 4px 6px;
363
+ min-width: 0;
364
+ font-size: 11px;
365
+ color: var(--civitai-color-text-dimmed);
366
+ }
367
+ [data-civitai-ui='resource-card'] [data-civitai-ui-resource-actions] {
368
+ display: flex;
369
+ align-items: center;
370
+ flex: none;
371
+ gap: 6px;
372
+ }
373
+ [data-civitai-ui='resource-card'][data-variant='card'] [data-civitai-ui-resource-actions] {
374
+ padding: 0 6px 6px;
375
+ }
376
+
182
377
  /* ----- SegmentedControl ----- */
183
378
  [data-civitai-ui='segmented-control'] {
184
379
  display: inline-flex;
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,YAAY,IAAI,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,2FAA2F;AAC3F,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqL1B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,SAAS,KAAK,aAAa,KAAK,kBAAkB,EAAE,CAAC;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAc;IAC/C,MAAM,MAAM,GACV,GAAG,IAAI,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,gFAAgF;IAChF,4EAA4E;IAC5E,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,iEAAiE;IACjE,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,YAAY,GAAG,CAAC;QAAE,OAAO;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC5C,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACzC,KAAK,CAAC,WAAW,GAAG,kBAAkB,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,oEAAoE;QACpE,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,SAAS,CAAC,GAAG,EAAE;QACb,kBAAkB,EAAE,CAAC;IACvB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,YAAY,IAAI,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,2FAA2F;AAC3F,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkX1B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,SAAS,KAAK,aAAa,KAAK,kBAAkB,EAAE,CAAC;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAc;IAC/C,MAAM,MAAM,GACV,GAAG,IAAI,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,gFAAgF;IAChF,4EAA4E;IAC5E,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,iEAAiE;IACjE,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,YAAY,GAAG,CAAC;QAAE,OAAO;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC5C,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACzC,KAAK,CAAC,WAAW,GAAG,kBAAkB,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,oEAAoE;QACpE,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,SAAS,CAAC,GAAG,EAAE;QACb,kBAAkB,EAAE,CAAC;IACvB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civitai/blocks-react",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "React hooks and iframe transport for Civitai Apps. Pairs with @civitai/app-sdk/blocks.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,8 +31,8 @@
31
31
  "node": ">=20"
32
32
  },
33
33
  "dependencies": {
34
- "@civitai/theme": "0.3.1",
35
- "@civitai/components": "0.4.1"
34
+ "@civitai/components": "0.4.1",
35
+ "@civitai/theme": "0.3.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@civitai/app-sdk": ">=0.29.0 <1.0.0",
@@ -50,7 +50,7 @@
50
50
  "react-dom": "^19.0.0",
51
51
  "typescript": "^5.9.2",
52
52
  "vitest": "^4.1.11",
53
- "@civitai/app-sdk": "^0.37.0"
53
+ "@civitai/app-sdk": "^0.38.0"
54
54
  },
55
55
  "publishConfig": {
56
56
  "access": "public"