composeai 0.1.5 → 0.1.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "composeai",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "The modern React composer for AI applications — a drop-in Lexical-powered chat input with markdown, mentions, slash commands, attachments, voice, streaming stop, and opt-in plugins for copilots, chatbots, and agent UIs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
package/src/composer.css CHANGED
@@ -47,6 +47,17 @@
47
47
  font-family: var(--composer-font-family, inherit);
48
48
  }
49
49
 
50
+ /* iOS Safari zooms the whole page when a focused field's font-size is below
51
+ * 16px. On touch devices, floor the editor (and its placeholder) at 16px so
52
+ * tapping the composer never triggers that zoom — while still honouring a
53
+ * LARGER `--composer-font-size` the consumer may have set, via `max()`. */
54
+ @media (pointer: coarse) {
55
+ [data-composer-root] .composer-editor,
56
+ [data-composer-root] .composer-placeholder {
57
+ font-size: max(16px, var(--composer-font-size, 15px));
58
+ }
59
+ }
60
+
50
61
  .composer-editor {
51
62
  position: relative;
52
63
  display: block;
@@ -252,9 +263,18 @@
252
263
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
253
264
  font-size: 13px;
254
265
  line-height: 1.55;
255
- background: hsl(var(--muted));
266
+ /* Translucent so the live diagram watermark (.composer-mermaid-backdrop)
267
+ * behind the fence shows through while the source stays readable. */
268
+ background: hsl(var(--muted) / 0.6);
256
269
  padding: 0.125rem 0.625rem;
257
270
  border-inline-start: 3px solid hsl(var(--primary) / 0.4);
271
+ /* The card is rounded (--composer-radius) but not `overflow: hidden` (that
272
+ * would clip the upward popovers). The editor's own padding is small, so a
273
+ * full-bleed code block's square corners poke past the card's rounded
274
+ * corners. Inset the block horizontally and break long tokens so the grey
275
+ * fill always stays inside the card outline. */
276
+ margin-inline: 0.5rem;
277
+ overflow-wrap: anywhere;
258
278
  }
259
279
  .composer-paragraph[data-md-block^="code-"] + .composer-paragraph[data-md-block^="code-"] {
260
280
  margin-top: 0;
@@ -284,6 +304,31 @@
284
304
  margin-inline-end: 0.5rem;
285
305
  }
286
306
 
307
+ /* Syntax highlighting for fenced code (mermaid). Each token is a CodeTokenNode
308
+ * with a `--<kind>` class. Colours are overridable via `--composer-code-*`
309
+ * custom properties; the defaults read on both light and the translucent code
310
+ * fill. `ident` / `text` deliberately inherit the editor foreground. */
311
+ .composer-code-tok--keyword {
312
+ color: var(--composer-code-keyword, hsl(280 58% 58%));
313
+ font-weight: 600;
314
+ }
315
+ .composer-code-tok--arrow {
316
+ color: var(--composer-code-arrow, hsl(190 72% 38%));
317
+ }
318
+ .composer-code-tok--string {
319
+ color: var(--composer-code-string, hsl(150 46% 38%));
320
+ }
321
+ .composer-code-tok--comment {
322
+ color: var(--composer-code-comment, hsl(var(--muted-foreground)));
323
+ font-style: italic;
324
+ }
325
+ .composer-code-tok--number {
326
+ color: var(--composer-code-number, hsl(28 78% 48%));
327
+ }
328
+ .composer-code-tok--punct {
329
+ color: var(--composer-code-punct, hsl(var(--muted-foreground)));
330
+ }
331
+
287
332
  .composer-paragraph[data-md-block="hr"] {
288
333
  position: relative;
289
334
  color: transparent;
@@ -500,7 +545,7 @@
500
545
  margin-top: 0;
501
546
  }
502
547
 
503
- /* The MermaidSlot is already gated out by the React tree when multiline is
548
+ /* The mermaid preview is already gated out by the React tree when multiline is
504
549
  * false, but this defensive rule keeps any stray `[data-mermaid-tile]` from
505
550
  * showing if a consumer renders one manually inside an inline composer. */
506
551
  [data-composer-root][data-composer-inline] [data-mermaid-tile] {
@@ -536,6 +581,10 @@
536
581
  * ------------------------------------------------------------------------- */
537
582
  .composer-root,
538
583
  [data-composer-scope] {
584
+ /* Light is the baseline. Pinned explicitly so the composer's own native
585
+ * UI (caret, scrollbars) stays light even when the user's OS prefers dark
586
+ * but the host app is rendering light. */
587
+ color-scheme: light;
539
588
  --background: 0 0% 100%;
540
589
  --foreground: 222 18% 18%;
541
590
  --card: 0 0% 100%;
@@ -564,12 +613,23 @@
564
613
  0 20px 48px -20px hsl(220 13% 10% / 0.4);
565
614
  }
566
615
 
567
- /* Auto dark theme for hosts whose users prefer dark keeps the composer
568
- * readable out of the box on a dark canvas. A consumer who wants an explicit
569
- * theme regardless of OS setting passes `tokens` (which wins inline). */
570
- @media (prefers-color-scheme: dark) {
571
- .composer-root,
572
- [data-composer-scope] {
616
+ /* Dark theme applied when the HOST app signals dark via the conventional
617
+ * `.dark` class or `[data-theme="dark"]` on any ancestor (the Tailwind /
618
+ * shadcn convention), so the composer follows the APP's theme, NOT the OS.
619
+ * A composer on a light app whose user's OS prefers dark therefore stays
620
+ * light — the host is the source of truth.
621
+ *
622
+ * (Previously this was an `@media (prefers-color-scheme: dark)` query, which
623
+ * darkened the composer based on the OS even when the surrounding app was
624
+ * light — the mismatch this replaces.)
625
+ *
626
+ * Consumers with custom theming are unaffected: `color` / `tokens` / `sx`
627
+ * apply inline on the scope element and always win over this stylesheet. */
628
+ .dark .composer-root,
629
+ .dark [data-composer-scope],
630
+ [data-theme="dark"] .composer-root,
631
+ [data-theme="dark"] [data-composer-scope] {
632
+ color-scheme: dark;
573
633
  --background: 222 16% 11%;
574
634
  --foreground: 210 20% 92%;
575
635
  --card: 222 16% 13%;
@@ -596,7 +656,6 @@
596
656
  0 12px 32px -16px hsl(0 0% 0% / 0.6);
597
657
  --composer-shadow-pop: 0 4px 12px hsl(0 0% 0% / 0.5),
598
658
  0 20px 48px -20px hsl(0 0% 0% / 0.7);
599
- }
600
659
  }
601
660
 
602
661
  /* Shared keyframes / animation helpers. `composer-popover-in` already exists
@@ -749,6 +808,22 @@
749
808
  .composer-editor-block {
750
809
  position: relative;
751
810
  min-width: 0;
811
+ /* Own stacking context so the mermaid watermark (z-index: -1) tucks behind
812
+ * the editor text but still paints over the card background. */
813
+ isolation: isolate;
814
+ }
815
+
816
+ /* Live diagram watermark behind a ```mermaid code box. Measured + positioned
817
+ * imperatively (see DiagramBackdrop); we only theme it here. Sits beneath the
818
+ * translucent code fill and never intercepts clicks. */
819
+ .composer-mermaid-backdrop {
820
+ position: absolute;
821
+ z-index: -1;
822
+ pointer-events: none;
823
+ background-repeat: no-repeat;
824
+ background-position: center;
825
+ background-size: contain;
826
+ opacity: 0.16;
752
827
  }
753
828
  .composer-editor-block--inline {
754
829
  flex: 1 1 0%;
@@ -789,6 +864,83 @@
789
864
  align-items: center;
790
865
  }
791
866
 
867
+ /* ----------------------------------------------------------------------------
868
+ * Compact variant layout — the slim chat-bar: a single growable row of
869
+ * [ + ] [ editor ] [ voice · send ]. The "+" and the trailing cluster
870
+ * bottom-align so they stay pinned to the last line as the editor grows.
871
+ * ------------------------------------------------------------------------- */
872
+ .composer-compact-row {
873
+ display: flex;
874
+ align-items: flex-end;
875
+ gap: 0.25rem;
876
+ padding: 0.375rem 0.5rem;
877
+ }
878
+ .composer-compact-actions,
879
+ .composer-compact-send {
880
+ display: flex;
881
+ flex: none;
882
+ align-items: center;
883
+ gap: 0.25rem;
884
+ /* Pin to the bottom edge of the row so the controls line up with the last
885
+ * line of a multi-line draft (not floated to the vertical center). */
886
+ align-self: flex-end;
887
+ /* Keep a ~36px control band so single-line resting state lines up with the
888
+ * compact editor's min-height. */
889
+ min-height: 2.25rem;
890
+ }
891
+
892
+ /* Expanded compact bar — the actions footer beneath the full-width editor.
893
+ * `+` sits at the start, the voice·send cluster at the end. */
894
+ .composer-compact-footer {
895
+ display: flex;
896
+ align-items: center;
897
+ justify-content: space-between;
898
+ gap: 0.25rem;
899
+ padding: 0.125rem 0.5rem 0.375rem;
900
+ }
901
+
902
+ .composer-editor.composer-editor--compact {
903
+ min-height: 2.25rem; /* one line ≈ the control band height */
904
+ max-height: 12rem;
905
+ overflow-y: auto;
906
+ padding: 0.4375rem 0.5rem; /* ~7px top/bottom centers one line in 36px */
907
+ line-height: 1.5;
908
+ scrollbar-width: thin;
909
+ scrollbar-color: hsl(var(--border)) transparent;
910
+ }
911
+ .composer-editor--compact::-webkit-scrollbar {
912
+ width: 6px;
913
+ }
914
+ .composer-editor--compact::-webkit-scrollbar-thumb {
915
+ background: hsl(var(--border));
916
+ border-radius: 9999px;
917
+ }
918
+
919
+ .composer-placeholder--compact {
920
+ inset-inline: 0;
921
+ top: 0;
922
+ padding: 0.4375rem 0.5rem;
923
+ line-height: 1.5;
924
+ white-space: nowrap;
925
+ overflow: hidden;
926
+ text-overflow: ellipsis;
927
+ }
928
+
929
+ /* Quick-actions ("+") popover. Reuses .composer-attach-menu visuals; the
930
+ * trigger wrapper just needs relative positioning for the absolute menu, and
931
+ * any `toolbarExtras` get a divider above them. */
932
+ .composer-quick-actions {
933
+ position: relative;
934
+ }
935
+ .composer-quick-extras {
936
+ display: flex;
937
+ flex-direction: column;
938
+ gap: 0.25rem;
939
+ margin-top: 0.25rem;
940
+ padding-top: 0.25rem;
941
+ border-top: 1px solid hsl(var(--border));
942
+ }
943
+
792
944
  .composer-toolbar-row {
793
945
  display: flex;
794
946
  align-items: center;
@@ -822,6 +974,18 @@
822
974
  background: hsl(var(--accent));
823
975
  color: hsl(var(--foreground));
824
976
  }
977
+ /* Toggle-style custom actions (active: true) light up in the brand accent.
978
+ * The voice button's own pressed rule is more specific + later in the file,
979
+ * so it still wins for the mic. */
980
+ .composer-toolbar-btn[aria-pressed="true"],
981
+ .composer-toolbar-btn[data-active] {
982
+ background: hsl(var(--accent));
983
+ color: hsl(var(--accent-foreground));
984
+ }
985
+ .composer-toolbar-btn:disabled {
986
+ opacity: 0.45;
987
+ cursor: default;
988
+ }
825
989
  .composer-toolbar-btn svg {
826
990
  height: 1rem;
827
991
  width: 1rem;
@@ -1406,6 +1570,14 @@
1406
1570
  border-top: 1px solid hsl(var(--border) / 0.6);
1407
1571
  background: hsl(var(--muted) / 0.3);
1408
1572
  padding: 0.75rem 1rem;
1573
+ /* The preview is the card's last, full-bleed child. The card is rounded but
1574
+ * isn't `overflow: hidden` (that would clip the upward-opening "+" /
1575
+ * attachment popovers), so without this the footer's square bottom corners
1576
+ * poke past the card's rounded edge. Match the card's inner radius (outer
1577
+ * radius minus the 1px border) so the footer tucks inside the corner. */
1578
+ border-end-start-radius: calc(var(--composer-radius, 28px) - 1px);
1579
+ border-end-end-radius: calc(var(--composer-radius, 28px) - 1px);
1580
+ overflow: hidden;
1409
1581
  }
1410
1582
  .composer-mermaid-head {
1411
1583
  display: flex;
@@ -1447,6 +1619,23 @@
1447
1619
  height: 6rem;
1448
1620
  width: 10rem;
1449
1621
  }
1622
+
1623
+ /* Compact variant: a slim strip of small thumbnails (no header banner). Each
1624
+ * tile is a "quick image" the user taps to open the full diagram in the
1625
+ * lightbox. */
1626
+ .composer-mermaid--compact {
1627
+ padding: 0.375rem 0.5rem;
1628
+ }
1629
+ .composer-mermaid--compact .composer-mermaid-svg {
1630
+ height: 2.75rem;
1631
+ width: 4.25rem;
1632
+ }
1633
+ .composer-mermaid--compact .composer-mermaid-zoom {
1634
+ height: 1rem;
1635
+ width: 1rem;
1636
+ inset-inline-end: 0.125rem;
1637
+ top: 0.125rem;
1638
+ }
1450
1639
  .composer-mermaid-svg svg {
1451
1640
  height: 100%;
1452
1641
  width: 100%;
@@ -1495,6 +1684,70 @@
1495
1684
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1496
1685
  }
1497
1686
 
1687
+ /* Compact variant: the diagram preview collapses behind a small live
1688
+ * thumbnail that sits beside the "+". A count badge appears when more than one
1689
+ * diagram is detected; pressing it opens the full tiles in an upward popover. */
1690
+ .composer-mermaid-trigger {
1691
+ position: relative;
1692
+ display: inline-flex;
1693
+ align-items: center;
1694
+ justify-content: center;
1695
+ height: 1.875rem;
1696
+ width: 2.75rem;
1697
+ padding: 0;
1698
+ overflow: hidden;
1699
+ border: 1px solid hsl(var(--border));
1700
+ border-radius: 0.5rem;
1701
+ background: hsl(var(--card));
1702
+ cursor: pointer;
1703
+ transition: border-color 0.15s ease;
1704
+ }
1705
+ .composer-mermaid-trigger:hover,
1706
+ .composer-mermaid-trigger[data-active] {
1707
+ border-color: hsl(var(--primary) / 0.4);
1708
+ }
1709
+ .composer-mermaid-thumb {
1710
+ display: block;
1711
+ height: 100%;
1712
+ width: 100%;
1713
+ }
1714
+ .composer-mermaid-thumb svg {
1715
+ height: 100%;
1716
+ width: 100%;
1717
+ object-fit: contain;
1718
+ }
1719
+ .composer-mermaid-count {
1720
+ position: absolute;
1721
+ top: -0.125rem;
1722
+ inset-inline-end: -0.125rem;
1723
+ display: flex;
1724
+ min-width: 0.875rem;
1725
+ height: 0.875rem;
1726
+ align-items: center;
1727
+ justify-content: center;
1728
+ padding-inline: 0.1875rem;
1729
+ border-radius: 9999px;
1730
+ background: hsl(var(--primary));
1731
+ color: hsl(var(--primary-foreground));
1732
+ font-size: 9px;
1733
+ font-weight: 600;
1734
+ line-height: 1;
1735
+ }
1736
+ .composer-mermaid-pop {
1737
+ position: absolute;
1738
+ bottom: 100%;
1739
+ inset-inline-start: 0;
1740
+ z-index: 30;
1741
+ margin-bottom: 0.5rem;
1742
+ max-width: min(80vw, 26rem);
1743
+ border-radius: 0.75rem;
1744
+ border: 1px solid hsl(var(--border));
1745
+ background: hsl(var(--popover));
1746
+ color: hsl(var(--popover-foreground));
1747
+ padding: 0.625rem 0.75rem;
1748
+ box-shadow: var(--composer-shadow-pop);
1749
+ }
1750
+
1498
1751
  /* ----------------------------------------------------------------------------
1499
1752
  * Hint bar + keyboard chips.
1500
1753
  * ------------------------------------------------------------------------- */