composeai 0.1.4 → 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/README.md +25 -1
- package/dist/index.cjs +817 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -18
- package/dist/index.d.ts +141 -18
- package/dist/index.js +819 -78
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/composer.css +262 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "composeai",
|
|
3
|
-
"version": "0.1.
|
|
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
|
-
|
|
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
|
|
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
|
-
/*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
* ------------------------------------------------------------------------- */
|