@crewlethq/ui 0.17.0 → 0.18.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 (146) hide show
  1. package/README.md +36 -1
  2. package/dist/AccessDeniedCard/AccessDeniedCard.d.ts +39 -0
  3. package/dist/AccessDeniedCard/index.d.ts +3 -0
  4. package/dist/AccessDeniedCard/index.js +8 -0
  5. package/dist/AccessDeniedCard-WXM5DBDZ.css +8 -0
  6. package/dist/ArtifactCard/ArtifactCard.d.ts +61 -0
  7. package/dist/ArtifactCard/index.d.ts +3 -0
  8. package/dist/ArtifactCard/index.js +12 -0
  9. package/dist/ArtifactCard-EXVAEBV6.css +109 -0
  10. package/dist/AvatarPicker/index.js +4 -4
  11. package/dist/ChangeMark/ChangeMark.d.ts +26 -0
  12. package/dist/ChangeMark/index.d.ts +3 -0
  13. package/dist/ChangeMark/index.js +8 -0
  14. package/dist/ChangeMark-3VMTW7MT.css +22 -0
  15. package/dist/Combobox/index.js +1 -1
  16. package/dist/CommandPalette/index.js +3 -3
  17. package/dist/CursorFlag/CursorFlag.d.ts +34 -0
  18. package/dist/CursorFlag/index.d.ts +3 -0
  19. package/dist/CursorFlag/index.js +3 -0
  20. package/dist/CursorFlag-AJQJBUGY.css +61 -0
  21. package/dist/DataTable/index.js +6 -6
  22. package/dist/DataView/index.js +12 -12
  23. package/dist/DateTimePicker/index.js +2 -2
  24. package/dist/FollowBanner/FollowBanner.d.ts +35 -0
  25. package/dist/FollowBanner/index.d.ts +2 -0
  26. package/dist/FollowBanner/index.js +7 -0
  27. package/dist/FrameProtocol/index.d.ts +2 -0
  28. package/dist/FrameProtocol/index.js +2 -0
  29. package/dist/FrameProtocol/protocol.d.ts +164 -0
  30. package/dist/HuePicker/index.js +2 -2
  31. package/dist/LinkInterstitial/LinkInterstitial.d.ts +41 -0
  32. package/dist/LinkInterstitial/index.d.ts +3 -0
  33. package/dist/LinkInterstitial/index.js +11 -0
  34. package/dist/LinkInterstitial-ET4MSVSV.css +34 -0
  35. package/dist/ListInput/index.js +1 -1
  36. package/dist/LiveCursor/LiveCursor.d.ts +34 -0
  37. package/dist/LiveCursor/index.d.ts +3 -0
  38. package/dist/LiveCursor/index.js +4 -0
  39. package/dist/LiveCursor-DZHGIYWE.css +47 -0
  40. package/dist/MarkdownEditor/index.js +2 -2
  41. package/dist/Modal/index.js +2 -2
  42. package/dist/OrgTable/index.js +2 -2
  43. package/dist/PresenceModel/index.d.ts +2 -0
  44. package/dist/PresenceModel/index.js +3 -0
  45. package/dist/PresenceModel/presence.d.ts +80 -0
  46. package/dist/PresenceRing/PresenceRing.d.ts +31 -0
  47. package/dist/PresenceRing/index.d.ts +3 -0
  48. package/dist/PresenceRing/index.js +2 -0
  49. package/dist/PresenceRing-M4C22Q6U.css +68 -0
  50. package/dist/PresenceStack/PresenceStack.d.ts +36 -0
  51. package/dist/PresenceStack/index.d.ts +3 -0
  52. package/dist/PresenceStack/index.js +9 -0
  53. package/dist/PresenceStack-QSXQJND5.css +59 -0
  54. package/dist/PricingCard/index.js +2 -2
  55. package/dist/Principal/Principal.d.ts +35 -0
  56. package/dist/Principal/index.d.ts +2 -0
  57. package/dist/Principal/index.js +4 -0
  58. package/dist/PrincipalPicker/PrincipalPicker.d.ts +45 -0
  59. package/dist/PrincipalPicker/index.d.ts +3 -0
  60. package/dist/PrincipalPicker/index.js +12 -0
  61. package/dist/PrincipalPicker-7NNZTGUP.css +41 -0
  62. package/dist/SandboxedFrame/SandboxedFrame.d.ts +142 -0
  63. package/dist/SandboxedFrame/index.d.ts +3 -0
  64. package/dist/SandboxedFrame/index.js +8 -0
  65. package/dist/SandboxedFrame-L6HBQZCD.css +50 -0
  66. package/dist/ShareDialog/ShareDialog.d.ts +101 -0
  67. package/dist/ShareDialog/index.d.ts +5 -0
  68. package/dist/ShareDialog/index.js +19 -0
  69. package/dist/ShareDialog/roles.d.ts +10 -0
  70. package/dist/ShareDialog-YZ4F37MW.css +146 -0
  71. package/dist/SheetGrid/SheetGrid.d.ts +78 -0
  72. package/dist/SheetGrid/cells.d.ts +117 -0
  73. package/dist/SheetGrid/index.d.ts +5 -0
  74. package/dist/SheetGrid/index.js +18 -0
  75. package/dist/SheetGrid-4HOXDVIB.css +595 -0
  76. package/dist/SheetModel/clipboard.d.ts +37 -0
  77. package/dist/SheetModel/edits.d.ts +68 -0
  78. package/dist/SheetModel/index.d.ts +14 -0
  79. package/dist/SheetModel/index.js +3 -0
  80. package/dist/SheetModel/labels.d.ts +71 -0
  81. package/dist/SheetModel/navigation.d.ts +79 -0
  82. package/dist/SheetModel/options.d.ts +28 -0
  83. package/dist/SheetModel/types.d.ts +126 -0
  84. package/dist/SheetModel/values.d.ts +76 -0
  85. package/dist/SheetModel/view.d.ts +32 -0
  86. package/dist/Switcher/index.js +5 -5
  87. package/dist/Tag/Tag.d.ts +13 -0
  88. package/dist/Tag/index.js +1 -1
  89. package/dist/{Tag-4BRQS6GN.css → Tag-SRGTK5KI.css} +42 -0
  90. package/dist/TagsInput/index.js +2 -2
  91. package/dist/ThemeSwitcher/apply.d.ts +43 -0
  92. package/dist/ThemeSwitcher/index.d.ts +4 -2
  93. package/dist/ThemeSwitcher/index.js +3 -2
  94. package/dist/ThemeSwitcher/preferences.d.ts +2 -19
  95. package/dist/ThemeToggle/index.js +3 -2
  96. package/dist/TimeWindowPicker/index.js +3 -3
  97. package/dist/Timeline/Timeline.d.ts +7 -2
  98. package/dist/Timeline/index.js +1 -1
  99. package/dist/VersionTimeline/VersionTimeline.d.ts +76 -0
  100. package/dist/VersionTimeline/index.d.ts +3 -0
  101. package/dist/VersionTimeline/index.js +10 -0
  102. package/dist/VersionTimeline-EBJ6MIPJ.css +108 -0
  103. package/dist/{chunk-SBRE7IML.js → chunk-2ONWEDQT.js} +1 -1
  104. package/dist/chunk-2YR5ZPQ3.js +216 -0
  105. package/dist/chunk-3BYIWOTV.js +29 -0
  106. package/dist/chunk-3UAA4IWJ.js +98 -0
  107. package/dist/chunk-4KP4RC3O.js +25 -0
  108. package/dist/chunk-4U3GQ7D2.js +99 -0
  109. package/dist/chunk-5XACKNYR.js +53 -0
  110. package/dist/{chunk-RF5O4FYL.js → chunk-76FXDZAZ.js} +2 -2
  111. package/dist/chunk-A7EBCHEG.js +49 -0
  112. package/dist/{chunk-JCO3SIST.js → chunk-AQCV62K6.js} +1 -1
  113. package/dist/{chunk-O67VF5MS.js → chunk-AUQPBL4O.js} +2 -2
  114. package/dist/{chunk-HENOTGUV.js → chunk-BOW2VUCH.js} +2 -2
  115. package/dist/{chunk-UCYIRDND.js → chunk-DQSXWQMJ.js} +1 -1
  116. package/dist/chunk-ESKP3TXM.js +1 -0
  117. package/dist/chunk-F6V2PTN6.js +142 -0
  118. package/dist/chunk-FW7HN6AP.js +40 -0
  119. package/dist/chunk-FYXRWBJJ.js +1235 -0
  120. package/dist/{chunk-LOECRMHA.js → chunk-GFV4LJHH.js} +4 -3
  121. package/dist/chunk-I6POAB4V.js +20 -0
  122. package/dist/{chunk-PQ63NLFC.js → chunk-IFKBDRNJ.js} +1 -1
  123. package/dist/{chunk-XU4H6JQB.js → chunk-KVT3TJVG.js} +4 -4
  124. package/dist/chunk-LFZ45HV2.js +46 -0
  125. package/dist/{chunk-6TSZCBID.js → chunk-NP2C4Y4E.js} +1 -1
  126. package/dist/{chunk-FA2V2VT6.js → chunk-NZY77ZDU.js} +3 -3
  127. package/dist/chunk-PPAQFGS2.js +12 -0
  128. package/dist/chunk-S35G6PNC.js +80 -0
  129. package/dist/chunk-VYDFB6PJ.js +243 -0
  130. package/dist/chunk-WXAULPBH.js +135 -0
  131. package/dist/chunk-YM3GJHGW.js +69 -0
  132. package/dist/chunk-YYZRLLLY.js +822 -0
  133. package/dist/{chunk-K3OWD7BJ.js → chunk-Z24ZUSTX.js} +4 -19
  134. package/dist/chunk-ZXXDZJQN.js +36 -0
  135. package/dist/generated/index.d.ts +18 -0
  136. package/dist/generated/index.js +82 -62
  137. package/dist/index.js +82 -62
  138. package/dist/styles.css +1578 -149
  139. package/dist/utils/index.js +1 -1
  140. package/package.json +6 -6
  141. package/dist/{chunk-DEEVA6TV.js → chunk-2TZATTIU.js} +1 -1
  142. package/dist/{chunk-2UU5IGZI.js → chunk-5NVKTB6E.js} +1 -1
  143. package/dist/{chunk-CRVETI5L.js → chunk-CENOOTAV.js} +0 -0
  144. package/dist/{chunk-JF7X673Z.js → chunk-ERV5BUS3.js} +1 -1
  145. package/dist/{chunk-NXDEPUVG.js → chunk-PA4CYTBY.js} +1 -1
  146. package/dist/{chunk-77IEHFY4.js → chunk-QQGWES46.js} +1 -1
@@ -0,0 +1,2 @@
1
+ export { FollowBanner } from './FollowBanner.js';
2
+ export type { FollowBannerLabels, FollowBannerProps, FollowBannerState } from './FollowBanner.js';
@@ -0,0 +1,7 @@
1
+ export { FollowBanner } from '../chunk-FW7HN6AP.js';
2
+ import '../chunk-SVSCLHHI.js';
3
+ import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-HMPFGIWM.js';
5
+ import '../chunk-R25RGPUB.js';
6
+ import '../chunk-BZFWDIV6.js';
7
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,2 @@
1
+ export { applyFrameTheme, checkFrameSandbox, DEFAULT_FRAME_THEME, EXTERNAL_URL_MAX, externalUrl, FRAME_BRIDGE, FRAME_MESSAGE, FRAME_ORIGIN_MODES, FRAME_SANDBOX_TOKENS, frameFragment, frameOriginMatches, frameThemeMessage, httpOrigin, isFocusExit, isFrameNonce, negotiateBridge, parseFrameFragment, portTargetOrigin, readFrameHello, readFramePortMessage, readFrameTheme, readOpenLink, } from './protocol.js';
2
+ export type { FrameBridgeRange, FrameFragment, FrameHello, FrameOpenLinkMessage, FrameOriginMode, FramePortMessage, FrameSandboxVerdict, FrameTheme, FrameThemeMessage, } from './protocol.js';
@@ -0,0 +1,2 @@
1
+ export { DEFAULT_FRAME_THEME, EXTERNAL_URL_MAX, FRAME_BRIDGE, FRAME_MESSAGE, FRAME_ORIGIN_MODES, FRAME_SANDBOX_TOKENS, applyFrameTheme, checkFrameSandbox, externalUrl, frameFragment, frameOriginMatches, frameThemeMessage, httpOrigin, isFocusExit, isFrameNonce, negotiateBridge, parseFrameFragment, portTargetOrigin, readFrameHello, readFramePortMessage, readFrameTheme, readOpenLink } from '../chunk-F6V2PTN6.js';
2
+ import '../chunk-ZXXDZJQN.js';
@@ -0,0 +1,164 @@
1
+ import { type ThemeId } from '@crewlethq/tokens';
2
+ import { type DensityPreference, type ThemePreference } from '../ThemeSwitcher/apply.js';
3
+ /** The message names, on the window before the handshake and on the port after it. */
4
+ export declare const FRAME_MESSAGE: {
5
+ /** Frame to host, on the window: "I am the document you embedded, here is your nonce". */
6
+ readonly hello: "crewlet.hello";
7
+ /** Host to frame, on the window, carrying the transferred port. */
8
+ readonly port: "crewlet.port";
9
+ /** Host to frame, on the port: the reader's appearance changed. */
10
+ readonly theme: "crewlet.theme";
11
+ /** Frame to host, on the port: open this link outside the frame. */
12
+ readonly openLink: "crewlet.openLink";
13
+ /** Frame to host, on the port: give keyboard focus back to the page around the frame. */
14
+ readonly focusExit: "crewlet.focusExit";
15
+ };
16
+ /**
17
+ * The bridge protocol versions this host speaks, negotiated in the hello.
18
+ *
19
+ * The page-facing contract (`window.crewlet`) and the host-facing bridge are
20
+ * versioned apart: a page pins its contract for as long as it is published,
21
+ * while the bridge moves with the host, which supports the current version and
22
+ * the one before it.
23
+ */
24
+ export declare const FRAME_BRIDGE: {
25
+ readonly min: 1;
26
+ readonly max: 1;
27
+ };
28
+ /**
29
+ * How the engine isolated the artifact, as its `Frame.mode` says.
30
+ *
31
+ * `per_artifact` serves every artifact from an origin of its own, so its
32
+ * messages arrive from that origin. `shared` serves every artifact from one
33
+ * host with an opaque origin, so its messages arrive from `"null"` and only
34
+ * the source window and the nonce bind them to this frame.
35
+ */
36
+ export type FrameOriginMode = 'per_artifact' | 'shared';
37
+ export declare const FRAME_ORIGIN_MODES: readonly ["per_artifact", "shared"];
38
+ /** The reader's appearance, as the page around the frame resolved it. */
39
+ export interface FrameTheme {
40
+ mode: ThemePreference;
41
+ /** A theme id from `@crewlethq/tokens`. */
42
+ palette: ThemeId;
43
+ density: DensityPreference;
44
+ }
45
+ /** What a frame paints before the host has said anything: the system, the default theme, the unscaled step. */
46
+ export declare const DEFAULT_FRAME_THEME: FrameTheme;
47
+ /**
48
+ * The fragment the host appends to the engine's frame URL.
49
+ *
50
+ * A FRAGMENT, NEVER A QUERY. A browser never sends a fragment to a server and
51
+ * never writes it to a log, so the handshake nonce and the reader's appearance
52
+ * stay between the two documents. The theme is in it so the frame paints in
53
+ * the reader's palette on its first frame, before any message can arrive.
54
+ */
55
+ export declare function frameFragment(nonce: string, theme: FrameTheme): string;
56
+ /** What a frame reads back from its own fragment. Each value is checked; a bad one falls back. */
57
+ export interface FrameFragment {
58
+ /** The handshake nonce, or null when the fragment carries none. */
59
+ nonce: string | null;
60
+ theme: FrameTheme;
61
+ }
62
+ /**
63
+ * Reads a frame's own `location.hash`.
64
+ *
65
+ * A value that is not one of the allowed ones is dropped for its default
66
+ * rather than applied, because the fragment is a string anybody can edit by
67
+ * hand in the address of a page opened on its own.
68
+ */
69
+ export declare function parseFrameFragment(hash: string): FrameFragment;
70
+ /** Whether a nonce is the shape the engine mints. */
71
+ export declare function isFrameNonce(value: unknown): value is string;
72
+ /**
73
+ * The origin of an absolute http or https URL, or null.
74
+ *
75
+ * Only those two schemes: a frame served from `data:`, `blob:` or
76
+ * `javascript:` would inherit or forge an origin, and the frame policy has no
77
+ * answer for any of them.
78
+ */
79
+ export declare function httpOrigin(raw: string): string | null;
80
+ /** Whether a message's origin is the one this mode says the frame's document has. */
81
+ export declare function frameOriginMatches(mode: FrameOriginMode, expected: string, actual: string): boolean;
82
+ /**
83
+ * The `targetOrigin` the host posts the port with.
84
+ *
85
+ * Per artifact, the artifact's own origin: if the frame has navigated
86
+ * anywhere else in the meantime, the browser drops the message. An opaque
87
+ * origin cannot be named, so `"*"` is the only value that reaches it, and the
88
+ * port is posted to the verified source window in the same task as the
89
+ * verified hello, so no navigation can come between the check and the send.
90
+ */
91
+ export declare function portTargetOrigin(mode: FrameOriginMode, origin: string): string;
92
+ /**
93
+ * Every sandbox token a frame may carry, and when.
94
+ *
95
+ * The engine computes the attribute and the host sets it VERBATIM; this is a
96
+ * second check, so a host never embeds a policy the engine would never have
97
+ * written. There is no `allow-popups` at all: an external link goes through
98
+ * the bridge's `openLink`, which the page around the frame opens after an
99
+ * interstitial, with `noopener`.
100
+ */
101
+ export declare const FRAME_SANDBOX_TOKENS: Readonly<Record<string, 'always' | 'per_artifact' | 'declared'>>;
102
+ export type FrameSandboxVerdict = {
103
+ ok: true;
104
+ value: string;
105
+ } | {
106
+ ok: false;
107
+ refused: string[];
108
+ };
109
+ /** Checks the engine's sandbox attribute against the tokens a frame in this mode may carry. */
110
+ export declare function checkFrameSandbox(sandbox: string, mode: FrameOriginMode): FrameSandboxVerdict;
111
+ /** The range of bridge versions a runtime speaks. */
112
+ export interface FrameBridgeRange {
113
+ min: number;
114
+ max: number;
115
+ }
116
+ /** Frame to host: the first message, posted on the window. */
117
+ export interface FrameHello {
118
+ type: typeof FRAME_MESSAGE.hello;
119
+ nonce: string;
120
+ /** The page-facing contract the runtime implements, `major.minor.patch`. */
121
+ contract: string;
122
+ bridge: FrameBridgeRange;
123
+ }
124
+ /** Reads a hello, or null for anything that is not exactly one. */
125
+ export declare function readFrameHello(data: unknown): FrameHello | null;
126
+ /** The highest bridge version both ends speak, or null when they share none. */
127
+ export declare function negotiateBridge(offered: FrameBridgeRange, supported?: FrameBridgeRange): number | null;
128
+ /** Host to frame: the port message, posted on the window with the port transferred. */
129
+ export interface FramePortMessage {
130
+ type: typeof FRAME_MESSAGE.port;
131
+ bridge: number;
132
+ }
133
+ /** Reads a port message, or null. The port itself is the event's `ports[0]`. */
134
+ export declare function readFramePortMessage(data: unknown): FramePortMessage | null;
135
+ /** Host to frame: the reader's appearance, on the port. */
136
+ export interface FrameThemeMessage extends FrameTheme {
137
+ type: typeof FRAME_MESSAGE.theme;
138
+ }
139
+ export declare function frameThemeMessage(theme: FrameTheme): FrameThemeMessage;
140
+ /** Reads a theme message, or null when any of its three values is not an allowed one. */
141
+ export declare function readFrameTheme(data: unknown): FrameTheme | null;
142
+ /** Writes the three appearance attributes on a root element, the same way the application writes its own. */
143
+ export declare function applyFrameTheme(theme: FrameTheme, root?: Element | null): void;
144
+ /** Frame to host: open a link outside the frame. */
145
+ export interface FrameOpenLinkMessage {
146
+ type: typeof FRAME_MESSAGE.openLink;
147
+ url: string;
148
+ }
149
+ /** Reads an open-link request's raw URL, or null. Use `externalUrl` to decide whether it may be opened. */
150
+ export declare function readOpenLink(data: unknown): string | null;
151
+ /** Whether a port message asks for focus back. */
152
+ export declare function isFocusExit(data: unknown): boolean;
153
+ /** The longest link an artifact may ask the host to open. */
154
+ export declare const EXTERNAL_URL_MAX = 2048;
155
+ /**
156
+ * A link an artifact may ask to open, parsed, or null.
157
+ *
158
+ * Absolute `https:`, `http:` and `mailto:` only. `javascript:` and `data:`
159
+ * would run or render in the page that opens them; a relative link has no
160
+ * meaning outside the frame it was written in. A URL carrying a user name or
161
+ * password is refused too, because `https://bank.example@evil.example` is the
162
+ * classic way to make a destination read as somewhere it is not.
163
+ */
164
+ export declare function externalUrl(raw: string): URL | null;
@@ -1,8 +1,8 @@
1
1
  import '../chunk-EXHQ2QVW.js';
2
- export { HuePicker } from '../chunk-NXDEPUVG.js';
3
- import '../chunk-AYKXMIOR.js';
2
+ export { HuePicker } from '../chunk-PA4CYTBY.js';
4
3
  import '../chunk-26PEPONN.js';
5
4
  import '../chunk-4LDTQWS7.js';
5
+ import '../chunk-AYKXMIOR.js';
6
6
  import '../chunk-CBOICT64.js';
7
7
  import '../chunk-BHHIIK3M.js';
8
8
  import '../chunk-BZFWDIV6.js';
@@ -0,0 +1,41 @@
1
+ export interface LinkInterstitialLabels {
2
+ title: string;
3
+ /** The line naming who asked. Given the source's name, or none when the caller names no source. */
4
+ intro: (source: string | undefined) => string;
5
+ destination: string;
6
+ insecure: string;
7
+ open: string;
8
+ cancel: string;
9
+ }
10
+ /**
11
+ * Opens a link in a new browsing context that cannot reach back.
12
+ *
13
+ * `noopener` severs `window.opener`, so the page that opens cannot navigate
14
+ * the dashboard that opened it; `noreferrer` keeps the dashboard's address out
15
+ * of the request. Exported so every place that opens an artifact's link opens
16
+ * it the same way.
17
+ */
18
+ export declare function openExternal(url: URL): void;
19
+ export interface LinkInterstitialProps {
20
+ /** The link a page asked to open, already checked by `externalUrl`. The dialog is open while this is set. */
21
+ url: URL | null;
22
+ /** Who asked, in the words the reader knows it by: the artifact's title. */
23
+ source?: string | undefined;
24
+ /** Asked to close, after the link was opened or when the reader declined. */
25
+ onClose: () => void;
26
+ /** The link was opened. */
27
+ onOpened?: ((url: URL) => void) | undefined;
28
+ labels?: Partial<LinkInterstitialLabels> | undefined;
29
+ }
30
+ /**
31
+ * The stop between an artifact's link and the open web.
32
+ *
33
+ * AN ARTIFACT NEVER OPENS A WINDOW. Its frame has no popup token at all, so a
34
+ * link reaches the page around it through the bridge, and this dialog names
35
+ * the destination before anything is opened: the host in large type, because
36
+ * the host is the claim a reader is deciding whether to trust, then the whole
37
+ * address. The host is the ASCII form the URL parser gives, so a name drawn in
38
+ * look-alike letters from another script shows as the `xn--` form it really
39
+ * is.
40
+ */
41
+ export declare function LinkInterstitial({ url, source, onClose, onOpened, labels }: LinkInterstitialProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './LinkInterstitial.css';
2
+ export { LinkInterstitial, openExternal } from './LinkInterstitial.js';
3
+ export type { LinkInterstitialLabels, LinkInterstitialProps } from './LinkInterstitial.js';
@@ -0,0 +1,11 @@
1
+ export { LinkInterstitial, openExternal } from '../chunk-A7EBCHEG.js';
2
+ import '../chunk-2TZATTIU.js';
3
+ import '../chunk-5CLW2CXT.js';
4
+ import '../chunk-SVSCLHHI.js';
5
+ import '../chunk-OG6CL3EB.js';
6
+ import '../chunk-4FQT6ZAY.js';
7
+ import '../chunk-HMPFGIWM.js';
8
+ import '../chunk-R25RGPUB.js';
9
+ import '../chunk-PQADV6P6.js';
10
+ import '../chunk-BZFWDIV6.js';
11
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,34 @@
1
+ /*
2
+ * The destination, said twice: the host as the claim a reader decides on, in
3
+ * the title's register, then the whole address in mono for whoever wants to
4
+ * read it exactly. The address wraps anywhere, because a long URL that does
5
+ * not wrap pushes the dialog wider than a phone.
6
+ */
7
+
8
+ .crewlet-link-interstitial {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--spacing-2);
12
+ padding: var(--spacing-3);
13
+ border-radius: var(--radius-md);
14
+ background: var(--color-surface-inset);
15
+ }
16
+
17
+ .crewlet-link-interstitial__label {
18
+ color: var(--color-text-tertiary);
19
+ font-size: var(--font-size-xs);
20
+ font-weight: var(--font-weight-medium);
21
+ }
22
+
23
+ .crewlet-link-interstitial__host {
24
+ color: var(--color-text-primary);
25
+ font-size: var(--font-size-lg);
26
+ font-weight: var(--font-weight-semibold);
27
+ overflow-wrap: anywhere;
28
+ }
29
+
30
+ .crewlet-link-interstitial__href {
31
+ align-self: flex-start;
32
+ max-width: 100%;
33
+ overflow-wrap: anywhere;
34
+ }
@@ -3,8 +3,8 @@ import '../chunk-SMBKXWML.js';
3
3
  import '../chunk-4GB57WIT.js';
4
4
  import '../chunk-RSAQOKH3.js';
5
5
  import '../chunk-4FQT6ZAY.js';
6
- import '../chunk-PQADV6P6.js';
7
6
  import '../chunk-HMPFGIWM.js';
8
7
  import '../chunk-R25RGPUB.js';
8
+ import '../chunk-PQADV6P6.js';
9
9
  import '../chunk-BZFWDIV6.js';
10
10
  import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,34 @@
1
+ import type { NodeHue } from '../utils/nodeHue.js';
2
+ /** How long a cursor that stopped moving stays at full strength, and how long until it is hidden. */
3
+ export declare const LIVE_CURSOR_REST_MS = 5000;
4
+ export declare const LIVE_CURSOR_HIDE_MS = 30000;
5
+ export interface LiveCursorProps {
6
+ /** Position in px from the leading top corner of the nearest positioned ancestor. */
7
+ x: number;
8
+ y: number;
9
+ name: string;
10
+ hue: NodeHue;
11
+ kind?: 'human' | 'agent' | undefined;
12
+ /** Fades to 40% after this long without a move. */
13
+ idleAfterMs?: number | undefined;
14
+ /** Hidden after this long without a move. */
15
+ hideAfterMs?: number | undefined;
16
+ /**
17
+ * Glides between positions. A reduced-motion preference always jumps
18
+ * instead, whatever this says; false jumps for everybody.
19
+ */
20
+ interpolate?: boolean | undefined;
21
+ className?: string | undefined;
22
+ }
23
+ /**
24
+ * A collaborator's pointer, with their name flag, at a point on a board or a
25
+ * page that shares cursors.
26
+ *
27
+ * IT FADES AS IT RESTS: full strength while it moves, 40% after five seconds
28
+ * still, hidden after thirty, so a pointer somebody left over a chart does not
29
+ * stand there all afternoon. Under a reduced-motion preference it jumps from
30
+ * point to point and never glides; the flag still appears. DECORATIVE to
31
+ * assistive technology, like every presence mark: where people are is said in
32
+ * words in the presence list.
33
+ */
34
+ export declare function LiveCursor({ x, y, name, hue, kind, idleAfterMs, hideAfterMs, interpolate, className, }: LiveCursorProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './LiveCursor.css';
2
+ export { LIVE_CURSOR_HIDE_MS, LIVE_CURSOR_REST_MS, LiveCursor } from './LiveCursor.js';
3
+ export type { LiveCursorProps } from './LiveCursor.js';
@@ -0,0 +1,4 @@
1
+ export { LIVE_CURSOR_HIDE_MS, LIVE_CURSOR_REST_MS, LiveCursor } from '../chunk-5XACKNYR.js';
2
+ import '../chunk-3BYIWOTV.js';
3
+ import '../chunk-I6POAB4V.js';
4
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,47 @@
1
+ /*
2
+ * A collaborator's live pointer and its flag (LiveCursor.tsx). It stands at a
3
+ * point by transform, so a moving cursor repaints without a layout, and the
4
+ * flag hangs below and after the pointer's tip.
5
+ */
6
+
7
+ .crewlet-live-cursor {
8
+ position: absolute;
9
+ top: 0;
10
+ left: 0;
11
+ z-index: var(--z-index-presence);
12
+ display: block;
13
+ pointer-events: none;
14
+ }
15
+
16
+ .crewlet-live-cursor__pointer {
17
+ display: block;
18
+ color: var(--crewlet-presence-hue);
19
+ }
20
+
21
+ .crewlet-live-cursor__flag {
22
+ position: absolute;
23
+ top: calc(var(--spacing-4) + var(--spacing-1));
24
+ left: var(--spacing-3);
25
+ }
26
+
27
+ .crewlet-live-cursor--resting {
28
+ opacity: 0.4;
29
+ }
30
+
31
+ .crewlet-live-cursor--gone {
32
+ display: none;
33
+ }
34
+
35
+ @media (prefers-reduced-motion: no-preference) {
36
+ .crewlet-live-cursor--glide {
37
+ transition:
38
+ transform var(--motion-duration-fast) linear,
39
+ opacity var(--motion-duration-base) var(--motion-easing-default);
40
+ }
41
+ }
42
+
43
+ @media (forced-colors: active) {
44
+ .crewlet-live-cursor__pointer {
45
+ color: Highlight;
46
+ }
47
+ }
@@ -1,10 +1,10 @@
1
- export { MARKDOWN_FORMATS, MarkdownEditor, formatMarkdown, insertMarkdown, markdownWords } from '../chunk-77IEHFY4.js';
1
+ export { MARKDOWN_FORMATS, MarkdownEditor, formatMarkdown, insertMarkdown, markdownWords } from '../chunk-QQGWES46.js';
2
2
  import '../chunk-VYY56AMX.js';
3
3
  import '../chunk-PGRPNDWM.js';
4
- import '../chunk-4FQT6ZAY.js';
5
4
  import '../chunk-26PEPONN.js';
6
5
  import '../chunk-4LDTQWS7.js';
7
6
  import '../chunk-CBOICT64.js';
7
+ import '../chunk-4FQT6ZAY.js';
8
8
  import '../chunk-HMPFGIWM.js';
9
9
  import '../chunk-R25RGPUB.js';
10
10
  import '../chunk-BHHIIK3M.js';
@@ -1,8 +1,8 @@
1
- export { ConfirmModal, Modal } from '../chunk-DEEVA6TV.js';
1
+ export { ConfirmModal, Modal } from '../chunk-2TZATTIU.js';
2
2
  import '../chunk-OG6CL3EB.js';
3
3
  import '../chunk-4FQT6ZAY.js';
4
- import '../chunk-PQADV6P6.js';
5
4
  import '../chunk-HMPFGIWM.js';
6
5
  import '../chunk-R25RGPUB.js';
6
+ import '../chunk-PQADV6P6.js';
7
7
  import '../chunk-BZFWDIV6.js';
8
8
  import '../chunk-ODEQTPFM.js';
@@ -5,9 +5,9 @@ import '../chunk-AKEZ3G5V.js';
5
5
  import '../chunk-VYOKRN2I.js';
6
6
  import '../chunk-TROLVEZY.js';
7
7
  import '../chunk-4FQT6ZAY.js';
8
- import '../chunk-UAN5NE7M.js';
9
8
  import '../chunk-HMPFGIWM.js';
10
9
  import '../chunk-R25RGPUB.js';
11
- import '../chunk-BZFWDIV6.js';
10
+ import '../chunk-UAN5NE7M.js';
12
11
  import '../chunk-5OM447RW.js';
12
+ import '../chunk-BZFWDIV6.js';
13
13
  import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,2 @@
1
+ export { PRESENCE_ACTIVITIES, PRESENCE_LABELS, assignPresenceHues, collapseSessions, joinNames, presenceLabels, presenceOrder, } from './presence.js';
2
+ export type { PresenceActivity, PresenceKind, PresenceLabels, PresenceMember } from './presence.js';
@@ -0,0 +1,3 @@
1
+ import '../chunk-CENOOTAV.js';
2
+ export { PRESENCE_ACTIVITIES, PRESENCE_LABELS, assignPresenceHues, collapseSessions, joinNames, presenceLabels, presenceOrder } from '../chunk-S35G6PNC.js';
3
+ import '../chunk-AYKXMIOR.js';
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Who is present in an artifact, as plain data: the order a roster is drawn
3
+ * in, the hue each collaborator's marks are drawn in, and the words a reader
4
+ * hears for both.
5
+ *
6
+ * FRAMEWORK FREE. Nothing here imports React or touches the document, because
7
+ * two renderers draw presence from it: the React components in this package,
8
+ * which the dashboard draws, and the artifact kit's custom elements, which an
9
+ * artifact page draws. A rule written once here cannot come to differ between
10
+ * the two.
11
+ *
12
+ * THE PRESENCE COLOUR IS THE NARROW EXCEPTION to colour carrying state. A
13
+ * collaborator's hue ties their cursor, their selection ring, their cell
14
+ * outline and their name flag to their name, and nothing else is drawn in it.
15
+ * An agent wears the hue an operator chose for it. A person is given one of
16
+ * the six node hues for the session, in join order, skipping the hues already
17
+ * in use in the room: never a hash of a name, and never stored on the person.
18
+ */
19
+ import { type NodeHue } from '../utils/nodeHue.js';
20
+ /** What a collaborator is doing: the engine's `artifacts.PresenceActivity`. */
21
+ export type PresenceActivity = 'editing' | 'viewing' | 'idle';
22
+ export declare const PRESENCE_ACTIVITIES: readonly ["editing", "viewing", "idle"];
23
+ /** A person, or an agent seat whose turn has the artifact open. */
24
+ export type PresenceKind = 'human' | 'agent';
25
+ /** One collaborator present in an artifact. */
26
+ export interface PresenceMember {
27
+ /** What tells two entries apart: a session, or a seat once tabs are collapsed. */
28
+ id: string;
29
+ /** The seat handle or principal the entry belongs to, so two tabs of one person collapse to one. */
30
+ seat?: string | undefined;
31
+ /** The display name, resolved by the host: the engine sends the seat handle only. */
32
+ name: string;
33
+ kind: PresenceKind;
34
+ activity: PresenceActivity;
35
+ /** The hue the collaborator's marks are drawn in. `assignPresenceHues` gives a person one. */
36
+ hue?: NodeHue | undefined;
37
+ /** An agent's Crewlet character, as `Avatar` draws it. */
38
+ character?: string | undefined;
39
+ /** A person's photo, as `Avatar` draws it. */
40
+ src?: string | undefined;
41
+ /** Where they are, in words: "Editing row Acme Corp", "Reading version 12 for ENG-412". */
42
+ location?: string | undefined;
43
+ }
44
+ export declare function presenceOrder<M extends Pick<PresenceMember, 'kind' | 'activity'>>(members: readonly M[]): M[];
45
+ /**
46
+ * One entry per seat: two tabs of one person are one collaborator, and the
47
+ * most active tab speaks for them. Entries with no seat are kept as they are.
48
+ * The first tab's position in the list is kept, so collapsing never reorders.
49
+ */
50
+ export declare function collapseSessions<M extends Pick<PresenceMember, 'id' | 'seat' | 'activity'>>(members: readonly M[]): M[];
51
+ /**
52
+ * The hue each member's marks are drawn in.
53
+ *
54
+ * An agent with a chosen hue keeps it. Every other member keeps the hue it was
55
+ * given before (`held`, the previous answer) while it stays present, and a
56
+ * newcomer, in the order given, takes the first of the six hues nobody present
57
+ * wears; past six, the hue the fewest members wear, so hues repeat as evenly
58
+ * as they can and the name on the flag tells the two apart.
59
+ */
60
+ export declare function assignPresenceHues(members: readonly Pick<PresenceMember, 'id' | 'kind' | 'hue'>[], held?: ReadonlyMap<string, NodeHue>): Map<string, NodeHue>;
61
+ /** Every string presence says, overridable wherever it is drawn. */
62
+ export interface PresenceLabels {
63
+ /** The activity word: "Editing", "Viewing", "Reading" for an agent viewing, "Idle". */
64
+ activity: (activity: PresenceActivity, kind: PresenceKind) => string;
65
+ /** The roster's accessible name. `others` counts everyone but the reader. */
66
+ here: (others: number, withSelf: boolean) => string;
67
+ /** One member, read out: "Maya Ortiz, editing row Acme Corp". */
68
+ member: (member: Pick<PresenceMember, 'name' | 'kind' | 'activity' | 'location'>) => string;
69
+ /** The members counted in the overflow chip: "3 more". */
70
+ more: (count: number) => string;
71
+ /** The flag on a cell somebody is editing: "Maya is editing". */
72
+ editing: (names: string) => string;
73
+ /** The words a focused cell gains when others are on it: "Jane Founder is also here." */
74
+ alsoHere: (names: readonly string[]) => string;
75
+ }
76
+ /** "Maya", "Maya and Jane", "Maya, Jane and 2 others". */
77
+ export declare function joinNames(names: readonly string[], shown?: number): string;
78
+ export declare const PRESENCE_LABELS: PresenceLabels;
79
+ /** Labels with a caller's overrides applied, the one way every component merges them. */
80
+ export declare function presenceLabels(overrides?: Partial<PresenceLabels>): PresenceLabels;
@@ -0,0 +1,31 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ import type { NodeHue } from '../utils/nodeHue.js';
3
+ /** A collaborator's hue, or `neutral` for a host that draws every collaborator alike. */
4
+ export type PresenceHue = NodeHue | 'neutral';
5
+ /** Active is a solid ring; idle is dashed, for a collaborator who has stepped away. */
6
+ export type PresenceRingState = 'active' | 'idle';
7
+ /**
8
+ * The class that sets `--crewlet-presence-hue` on an element, for a component
9
+ * that draws a presence mark of its own (a flag, a cursor, a badge's ring).
10
+ * One table of hues for every presence mark, so a hue cannot be spelt two ways.
11
+ */
12
+ export declare function presenceHueClass(hue: PresenceHue): string;
13
+ export interface PresenceRingProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'children'> {
14
+ hue: PresenceHue;
15
+ state?: PresenceRingState | undefined;
16
+ /** How far inside the element's edge the ring is drawn, in px. 1 by default, inside a hairline. */
17
+ inset?: number | undefined;
18
+ children?: ReactNode;
19
+ }
20
+ /**
21
+ * A collaborator's outline round whatever they are on: a cell, a card, an
22
+ * element of a page.
23
+ *
24
+ * INSET, so it never doubles the element's own border: the element keeps its
25
+ * one edge and the ring is drawn inside it. DECORATIVE: it is a pseudo element
26
+ * nothing reads, because the same fact is said in words where presence is
27
+ * listed and in the focused element's description ("Jane Founder is also
28
+ * here"). The hue is the presence colour exception (D22), so it is only ever
29
+ * drawn beside the collaborator's name.
30
+ */
31
+ export declare function PresenceRing({ hue, state, inset, className, style, children, ...rest }: PresenceRingProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './PresenceRing.css';
2
+ export { PresenceRing, presenceHueClass } from './PresenceRing.js';
3
+ export type { PresenceHue, PresenceRingProps, PresenceRingState } from './PresenceRing.js';
@@ -0,0 +1,2 @@
1
+ export { PresenceRing, presenceHueClass } from '../chunk-I6POAB4V.js';
2
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,68 @@
1
+ /*
2
+ * The presence hues and the ring drawn in them (PresenceRing.tsx).
3
+ *
4
+ * ONE TABLE OF HUES for every presence mark: a ring, a flag, a cursor and a
5
+ * badge's ring each read `--crewlet-presence-hue` from the class
6
+ * `presenceHueClass` writes, so the six node hues are spelt once. The hue is
7
+ * the presence colour exception: it ties a mark to a name and is spent on
8
+ * nothing else.
9
+ */
10
+
11
+ .crewlet-presence-hue--purple {
12
+ --crewlet-presence-hue: var(--color-node-purple);
13
+ }
14
+
15
+ .crewlet-presence-hue--cyan {
16
+ --crewlet-presence-hue: var(--color-node-cyan);
17
+ }
18
+
19
+ .crewlet-presence-hue--green {
20
+ --crewlet-presence-hue: var(--color-node-green);
21
+ }
22
+
23
+ .crewlet-presence-hue--amber {
24
+ --crewlet-presence-hue: var(--color-node-amber);
25
+ }
26
+
27
+ .crewlet-presence-hue--rose {
28
+ --crewlet-presence-hue: var(--color-node-rose);
29
+ }
30
+
31
+ .crewlet-presence-hue--blue {
32
+ --crewlet-presence-hue: var(--color-node-blue);
33
+ }
34
+
35
+ .crewlet-presence-hue--neutral {
36
+ --crewlet-presence-hue: var(--color-border-strong);
37
+ }
38
+
39
+ /*
40
+ * THE RING IS INSET and drawn on a pseudo element, so it never moves the
41
+ * content, never doubles the element's own border and is never read. 2px,
42
+ * the weight a selection ring is drawn at.
43
+ */
44
+ .crewlet-presence-ring {
45
+ --crewlet-presence-ring-inset: 1px;
46
+ position: relative;
47
+ display: inline-block;
48
+ }
49
+
50
+ .crewlet-presence-ring::after {
51
+ position: absolute;
52
+ inset: var(--crewlet-presence-ring-inset);
53
+ z-index: var(--z-index-presence);
54
+ border: 2px solid var(--crewlet-presence-hue);
55
+ border-radius: inherit;
56
+ content: '';
57
+ pointer-events: none;
58
+ }
59
+
60
+ .crewlet-presence-ring--idle::after {
61
+ border-style: dashed;
62
+ }
63
+
64
+ @media (forced-colors: active) {
65
+ .crewlet-presence-ring::after {
66
+ border-color: Highlight;
67
+ }
68
+ }