@crewlethq/ui 0.15.1 → 0.16.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 (111) hide show
  1. package/README.md +32 -6
  2. package/dist/AppShell/AccountRow.d.ts +40 -0
  3. package/dist/AppShell/AppShell.d.ts +1 -0
  4. package/dist/AppShell/index.d.ts +2 -0
  5. package/dist/AppShell/index.js +1 -1
  6. package/dist/{AppShell-6QUD7NWM.css → AppShell-RUNVM4WH.css} +93 -0
  7. package/dist/AuthLayout/AuthLayout.d.ts +35 -0
  8. package/dist/AuthLayout/index.d.ts +3 -0
  9. package/dist/AuthLayout/index.js +8 -0
  10. package/dist/AuthLayout-ODHBUPHQ.css +54 -0
  11. package/dist/Avatar/Avatar.d.ts +22 -2
  12. package/dist/Avatar/index.d.ts +1 -1
  13. package/dist/Avatar/index.js +2 -2
  14. package/dist/{Avatar-I4NFP3WQ.css → Avatar-MBUPR5E5.css} +19 -0
  15. package/dist/AvatarPicker/index.js +4 -4
  16. package/dist/Callout/Callout.d.ts +7 -1
  17. package/dist/Callout/index.js +1 -1
  18. package/dist/{Callout-S7QDWHDL.css → Callout-SXXK4B5R.css} +3 -1
  19. package/dist/CharacterPicker/index.js +2 -2
  20. package/dist/Checkbox/CheckboxGroup.d.ts +30 -0
  21. package/dist/Checkbox/index.d.ts +2 -0
  22. package/dist/Checkbox/index.js +5 -1
  23. package/dist/{Checkbox-UE7TEPAM.css → Checkbox-KT7RS6QQ.css} +16 -0
  24. package/dist/CodeBlock/index.js +4 -3
  25. package/dist/Combobox/index.js +3 -3
  26. package/dist/CommandPalette/index.js +5 -5
  27. package/dist/Composer/index.js +3 -3
  28. package/dist/ConfirmField/ConfirmField.d.ts +43 -0
  29. package/dist/ConfirmField/index.d.ts +2 -0
  30. package/dist/ConfirmField/index.js +7 -0
  31. package/dist/Copyable/CopyButton.d.ts +13 -6
  32. package/dist/Copyable/index.js +3 -2
  33. package/dist/DataTable/index.js +7 -5
  34. package/dist/DataView/index.js +12 -11
  35. package/dist/DateTimePicker/index.js +2 -2
  36. package/dist/DownloadButton/DownloadButton.d.ts +52 -0
  37. package/dist/DownloadButton/index.d.ts +2 -0
  38. package/dist/DownloadButton/index.js +6 -0
  39. package/dist/EntityChip/index.js +3 -3
  40. package/dist/ImageUpload/index.js +3 -3
  41. package/dist/InlineCode/InlineCode.d.ts +8 -1
  42. package/dist/InlineCode/index.js +1 -1
  43. package/dist/{InlineCode-6WSR5COL.css → InlineCode-ASYHLN3E.css} +9 -0
  44. package/dist/Input/index.js +2 -2
  45. package/dist/{Input-RAKNQJCV.css → Input-3KVSNUO5.css} +11 -0
  46. package/dist/ListInput/index.js +3 -3
  47. package/dist/MarkdownEditor/index.js +1 -1
  48. package/dist/Modal/index.js +2 -2
  49. package/dist/ObjectHeader/ObjectHeader.d.ts +138 -0
  50. package/dist/ObjectHeader/index.d.ts +3 -0
  51. package/dist/ObjectHeader/index.js +4 -0
  52. package/dist/ObjectHeader-UNVYM2KD.css +174 -0
  53. package/dist/OrgLabel/index.js +3 -3
  54. package/dist/OrgNode/index.js +4 -4
  55. package/dist/OrgTable/index.js +4 -4
  56. package/dist/QrCode/QrCode.d.ts +58 -0
  57. package/dist/QrCode/index.d.ts +3 -0
  58. package/dist/QrCode/index.js +2 -0
  59. package/dist/QrCode-JWJTWMU5.css +19 -0
  60. package/dist/Switcher/index.js +4 -4
  61. package/dist/Text/Text.d.ts +7 -1
  62. package/dist/Text/index.js +1 -1
  63. package/dist/{Text-XIPYYZX2.css → Text-S3Q4O3IG.css} +11 -0
  64. package/dist/TimeWindowPicker/index.js +4 -4
  65. package/dist/{chunk-FTEJPHBI.js → chunk-4GB57WIT.js} +2 -2
  66. package/dist/{chunk-NN62JQLR.js → chunk-5CLW2CXT.js} +3 -1
  67. package/dist/{chunk-4EOJR52M.js → chunk-5EFRWWGX.js} +4 -4
  68. package/dist/{chunk-22M7OXKW.js → chunk-6DQWF5Y4.js} +1 -1
  69. package/dist/{chunk-QSLIN64M.js → chunk-6NIMZ5XC.js} +1 -1
  70. package/dist/{chunk-YCTMKKRA.js → chunk-75CLJNDQ.js} +12 -2
  71. package/dist/chunk-7QFAORCY.js +37 -0
  72. package/dist/chunk-BJCFNRGH.js +53 -0
  73. package/dist/{chunk-FY2R4U4Q.js → chunk-CGNQPGJL.js} +1 -1
  74. package/dist/{chunk-DDTDN5L2.js → chunk-CKB3OHL3.js} +1 -1
  75. package/dist/chunk-CXBAIVYZ.js +39 -0
  76. package/dist/chunk-DTIW4CHZ.js +37 -0
  77. package/dist/{chunk-YXMCUKFI.js → chunk-DZ2YR6MV.js} +1 -1
  78. package/dist/{chunk-TK6YC5QT.js → chunk-EIOTVNYX.js} +4 -4
  79. package/dist/chunk-F6NZOVWL.js +68 -0
  80. package/dist/{chunk-LCF4WPYS.js → chunk-FA2V2VT6.js} +2 -2
  81. package/dist/{chunk-EFNHOVC2.js → chunk-FAEN3HYI.js} +2 -2
  82. package/dist/{chunk-HI6Q2UXQ.js → chunk-FY4SP3HF.js} +11 -3
  83. package/dist/{chunk-KGTQ5CVD.js → chunk-GDDE4UM7.js} +1 -1
  84. package/dist/chunk-I7WXZOWA.js +90 -0
  85. package/dist/{chunk-23DHIMJA.js → chunk-IKBK4A5O.js} +1 -1
  86. package/dist/{chunk-DY77H372.js → chunk-JF7X673Z.js} +2 -2
  87. package/dist/{chunk-DJMLHCLD.js → chunk-KLESCRTS.js} +1 -1
  88. package/dist/{chunk-YYBD73OI.js → chunk-OFMPIRGD.js} +1 -1
  89. package/dist/{chunk-H3XOMT7W.js → chunk-OYOQU7O5.js} +44 -3
  90. package/dist/{chunk-IYZZL3MZ.js → chunk-PQ63NLFC.js} +3 -3
  91. package/dist/{chunk-5VNUYO76.js → chunk-STJ7QBC3.js} +8 -25
  92. package/dist/{chunk-R6FBDTP3.js → chunk-SVSCLHHI.js} +1 -1
  93. package/dist/{chunk-GARACZAH.js → chunk-T3ZWBZ65.js} +1 -1
  94. package/dist/{chunk-ZPWUVVIB.js → chunk-UAMDRJD6.js} +2 -2
  95. package/dist/{chunk-YACKC3K2.js → chunk-W46LPU4R.js} +8 -8
  96. package/dist/chunk-Y56FM3K4.js +57 -0
  97. package/dist/{chunk-4Y7WKXAW.js → chunk-ZFH7H7GS.js} +1 -1
  98. package/dist/generated/index.d.ts +5 -0
  99. package/dist/generated/index.js +67 -60
  100. package/dist/index.js +67 -60
  101. package/dist/styles.css +425 -8
  102. package/dist/utils/index.d.ts +4 -0
  103. package/dist/utils/index.js +4 -2
  104. package/dist/utils/useClipboard.d.ts +6 -3
  105. package/dist/utils/useDownload.d.ts +63 -0
  106. package/dist/utils/useOutcome.d.ts +44 -0
  107. package/package.json +4 -3
  108. package/dist/{chunk-GUHP5JHC.js → chunk-2UU5IGZI.js} +1 -1
  109. package/dist/{chunk-6AR2T5Y4.js → chunk-CRVETI5L.js} +0 -0
  110. package/dist/{chunk-K4VORB64.js → chunk-DEEVA6TV.js} +1 -1
  111. /package/dist/{chunk-AER7UDD4.js → chunk-U5LQ2AS5.js} +0 -0
@@ -1,5 +1,5 @@
1
- export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from '../chunk-FY2R4U4Q.js';
2
- import '../chunk-22M7OXKW.js';
3
- import '../chunk-ZPWUVVIB.js';
4
- import '../chunk-HI6Q2UXQ.js';
1
+ export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from '../chunk-CGNQPGJL.js';
2
+ import '../chunk-6DQWF5Y4.js';
3
+ import '../chunk-UAMDRJD6.js';
4
+ import '../chunk-FY4SP3HF.js';
5
5
  import '../chunk-ODEQTPFM.js';
@@ -1,13 +1,13 @@
1
- export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from '../chunk-YYBD73OI.js';
1
+ export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from '../chunk-OFMPIRGD.js';
2
2
  import '../chunk-B2Z2CDM5.js';
3
3
  import '../chunk-MY374UUD.js';
4
- import '../chunk-22M7OXKW.js';
4
+ import '../chunk-6DQWF5Y4.js';
5
5
  import '../chunk-VYOKRN2I.js';
6
6
  import '../chunk-TROLVEZY.js';
7
7
  import '../chunk-4FQT6ZAY.js';
8
- import '../chunk-ZPWUVVIB.js';
8
+ import '../chunk-UAMDRJD6.js';
9
9
  import '../chunk-HMPFGIWM.js';
10
10
  import '../chunk-R25RGPUB.js';
11
11
  import '../chunk-BZFWDIV6.js';
12
- import '../chunk-HI6Q2UXQ.js';
12
+ import '../chunk-FY4SP3HF.js';
13
13
  import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * A QR code, drawn as inline SVG from the encoder's module matrix.
3
+ *
4
+ * INLINE SVG AND NOTHING ELSE. The encoder answers a matrix of booleans and
5
+ * this draws it as one `<path>` on one `<rect>`: not an `<img>` with a `data:`
6
+ * URI, not markup set as HTML, and nothing fetched. A strict
7
+ * Content-Security-Policy admits each of those only by being widened, and the
8
+ * value a QR code carries is often a credential (a second factor's seed),
9
+ * which must not leave the DOM it is shown in.
10
+ *
11
+ * BLACK ON A WHITE PLATE, IN EVERY THEME. A QR code is a symbol a camera reads,
12
+ * and its two inks are part of the symbol rather than colours of the palette.
13
+ * A code is specified dark on light, and some authenticator apps do not read
14
+ * one inverted for a dark theme, so it is never inverted. The inks are the
15
+ * `color.qr` tokens, which are the same in every palette, and they are written
16
+ * as the SVG's own fill attributes so the code draws correctly with no
17
+ * stylesheet at all. The plate keeps its inks under forced colours too.
18
+ *
19
+ * FOUR MODULES OF QUIET ZONE, AND LEVEL M. The margin a reader needs to find
20
+ * the finder patterns is four light modules on every side, the standard's own
21
+ * figure. Error correction is M, which still reads with 15% of the symbol
22
+ * lost and is the level authenticator codes are conventionally drawn at.
23
+ */
24
+ /** Light modules around the symbol, on every side. */
25
+ export declare const QR_QUIET_ZONE = 4;
26
+ /** The dark modules' ink: the `color.qr.dark` token. */
27
+ export declare const QR_DARK: string;
28
+ /** The plate's ink, the quiet zone included: the `color.qr.light` token. */
29
+ export declare const QR_LIGHT: string;
30
+ /**
31
+ * The symbol's modules for `value`, `true` for dark, row by row, or null for
32
+ * a value too long for any QR code to hold.
33
+ *
34
+ * NULL RATHER THAN A THROW. The encoder refuses an oversized value with a
35
+ * `RangeError`, and a code that cannot be drawn is an aid missing rather than
36
+ * a screen that should fall over: whoever renders one keeps the value's other
37
+ * forms beside it. Any other error is a fault and is not caught.
38
+ */
39
+ export declare function qrModules(value: string): boolean[][] | null;
40
+ /**
41
+ * The dark modules as one SVG path in module units: one rectangle per
42
+ * horizontal run of dark modules, so adjacent modules share an edge rather
43
+ * than meeting at two anti-aliased ones.
44
+ */
45
+ export declare function qrModulePath(modules: readonly (readonly boolean[])[]): string;
46
+ export interface QrCodeProps {
47
+ /** What the code encodes, exactly. */
48
+ value: string;
49
+ /** The image's accessible name: what the code is for, never the value itself. */
50
+ label: string;
51
+ className?: string | undefined;
52
+ }
53
+ /**
54
+ * `value` as a QR code, named by `label`, or nothing for a value no QR code
55
+ * can hold. Keep the value's other forms (a key to type, a link to open)
56
+ * beside it: a code is an aid, and not every reader has a camera.
57
+ */
58
+ export declare function QrCode({ value, label, className }: QrCodeProps): import("react").JSX.Element | null;
@@ -0,0 +1,3 @@
1
+ import './QrCode.css';
2
+ export { QR_DARK, QR_LIGHT, QR_QUIET_ZONE, QrCode, qrModulePath, qrModules } from './QrCode.js';
3
+ export type { QrCodeProps } from './QrCode.js';
@@ -0,0 +1,2 @@
1
+ export { QR_DARK, QR_LIGHT, QR_QUIET_ZONE, QrCode, qrModulePath, qrModules } from '../chunk-Y56FM3K4.js';
2
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,19 @@
1
+ /*
2
+ * A QR code on its own plate.
3
+ *
4
+ * A FIXED BOX, because a camera needs modules of a readable size: at 208px a
5
+ * second factor's code (a version 7 symbol and its quiet zone) draws each
6
+ * module at about 4.3px. A consumer that needs another size sets the variable.
7
+ *
8
+ * ITS INKS ARE KEPT UNDER FORCED COLOURS. A high-contrast mode repaints fills
9
+ * to system colours, and a plate repainted dark is a code no scanner reads.
10
+ */
11
+ .crewlet-qr-code {
12
+ --crewlet-qr-code-size: 208px;
13
+ display: block;
14
+ flex: none;
15
+ width: var(--crewlet-qr-code-size);
16
+ height: var(--crewlet-qr-code-size);
17
+ border-radius: var(--radius-sm);
18
+ forced-color-adjust: none;
19
+ }
@@ -1,14 +1,14 @@
1
- export { Switcher } from '../chunk-LCF4WPYS.js';
1
+ export { Switcher } from '../chunk-FA2V2VT6.js';
2
2
  import '../chunk-W5J7R5EB.js';
3
- import '../chunk-K4VORB64.js';
3
+ import '../chunk-DEEVA6TV.js';
4
4
  import '../chunk-F73MC7EZ.js';
5
- import '../chunk-FTEJPHBI.js';
5
+ import '../chunk-4GB57WIT.js';
6
6
  import '../chunk-FYTIJM2T.js';
7
7
  import '../chunk-OG6CL3EB.js';
8
- import '../chunk-PQADV6P6.js';
9
8
  import '../chunk-RSAQOKH3.js';
10
9
  import '../chunk-IG75YMUN.js';
11
10
  import '../chunk-4FQT6ZAY.js';
11
+ import '../chunk-PQADV6P6.js';
12
12
  import '../chunk-BWRGFKJP.js';
13
13
  import '../chunk-HMPFGIWM.js';
14
14
  import '../chunk-R25RGPUB.js';
@@ -20,7 +20,13 @@ export type TextVariant =
20
20
  /** A page title. */
21
21
  | 'display'
22
22
  /** A single measured number, the size a stat card sets it at. */
23
- | 'stat';
23
+ | 'stat'
24
+ /**
25
+ * The register of the words around it: their size, weight and ink. For a
26
+ * run inside a sentence or a chip that changes one thing about it, with
27
+ * `mono` for a literal (a login, a header name) or `numeric` for a figure.
28
+ */
29
+ | 'inherit';
24
30
  /**
25
31
  * Which ink. There is deliberately no decoration step here: the decoration
26
32
  * ink is measured into the 2.8 to 4.5:1 band on purpose, so it carries a
@@ -1,2 +1,2 @@
1
- export { Text } from '../chunk-23DHIMJA.js';
1
+ export { Text } from '../chunk-IKBK4A5O.js';
2
2
  import '../chunk-ODEQTPFM.js';
@@ -49,6 +49,17 @@
49
49
  color: var(--color-text-primary);
50
50
  }
51
51
 
52
+ /*
53
+ * The register around it: nothing is set, so the run keeps its sentence's
54
+ * size, weight, tracking and ink, and only a modifier (mono, numeric) or a
55
+ * tone changes it.
56
+ */
57
+ .crewlet-text--inherit {
58
+ font-size: inherit;
59
+ line-height: inherit;
60
+ color: inherit;
61
+ }
62
+
52
63
  .crewlet-text--body {
53
64
  font-size: var(--font-size-sm);
54
65
  line-height: var(--font-line-height-normal);
@@ -1,11 +1,11 @@
1
- export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-DY77H372.js';
1
+ export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-JF7X673Z.js';
2
2
  import '../chunk-FC4YTTFJ.js';
3
3
  import '../chunk-F73MC7EZ.js';
4
- import '../chunk-FTEJPHBI.js';
5
- import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-4GB57WIT.js';
6
5
  import '../chunk-GXQ3B46I.js';
7
- import '../chunk-PQADV6P6.js';
6
+ import '../chunk-OG6CL3EB.js';
8
7
  import '../chunk-4FQT6ZAY.js';
8
+ import '../chunk-PQADV6P6.js';
9
9
  import '../chunk-BWRGFKJP.js';
10
10
  import '../chunk-HMPFGIWM.js';
11
11
  import '../chunk-R25RGPUB.js';
@@ -1,8 +1,8 @@
1
- import { useHeadingLevel, headingTag, HeadingLevelProvider, nextHeadingLevel } from './chunk-PQADV6P6.js';
2
1
  import { IconButton } from './chunk-4FQT6ZAY.js';
2
+ import { useHeadingLevel, headingTag, HeadingLevelProvider, nextHeadingLevel } from './chunk-PQADV6P6.js';
3
3
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
- import './Input-RAKNQJCV.css';
5
+ import './Input-3KVSNUO5.css';
6
6
  import { forwardRef, useRef, useState, useImperativeHandle, useEffect, useId } from 'react';
7
7
  import { XGlyph } from '@crewlethq/icons/glyphs';
8
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,11 +1,12 @@
1
1
  import { cx } from './chunk-ODEQTPFM.js';
2
- import './InlineCode-6WSR5COL.css';
2
+ import './InlineCode-ASYHLN3E.css';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function InlineCode({
6
6
  variant = "default",
7
7
  tone = "default",
8
8
  truncate = false,
9
+ whole = false,
9
10
  className,
10
11
  children,
11
12
  ...rest
@@ -19,6 +20,7 @@ function InlineCode({
19
20
  `crewlet-inline-code--${variant}`,
20
21
  tone === "inherit" && "crewlet-inline-code--inherit",
21
22
  truncate && "crewlet-inline-code--truncate",
23
+ whole && "crewlet-inline-code--whole",
22
24
  className
23
25
  ),
24
26
  children
@@ -1,12 +1,12 @@
1
- import { PageHeader } from './chunk-HOXGBLEY.js';
2
1
  import { RelativeTime } from './chunk-3CZ7XAVY.js';
2
+ import { PageHeader } from './chunk-HOXGBLEY.js';
3
3
  import { Toolbar } from './chunk-PGRPNDWM.js';
4
- import { DataTable } from './chunk-TK6YC5QT.js';
4
+ import { DataTable } from './chunk-EIOTVNYX.js';
5
5
  import { Menu } from './chunk-NS7BVLL3.js';
6
- import { DateTimePicker } from './chunk-GUHP5JHC.js';
6
+ import { DateTimePicker } from './chunk-2UU5IGZI.js';
7
7
  import { useListbox, useOptionKeys } from './chunk-F73MC7EZ.js';
8
8
  import { Kbd } from './chunk-SMBKXWML.js';
9
- import { Input } from './chunk-FTEJPHBI.js';
9
+ import { Input } from './chunk-4GB57WIT.js';
10
10
  import { Button } from './chunk-OG6CL3EB.js';
11
11
  import { IconButton } from './chunk-4FQT6ZAY.js';
12
12
  import { Popover } from './chunk-BWRGFKJP.js';
@@ -1,4 +1,4 @@
1
- import { Avatar } from './chunk-HI6Q2UXQ.js';
1
+ import { Avatar } from './chunk-FY4SP3HF.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './OrgLabel-R5KY7C3W.css';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
1
  import { Kbd } from './chunk-SMBKXWML.js';
2
- import { Textarea } from './chunk-FTEJPHBI.js';
2
+ import { Textarea } from './chunk-4GB57WIT.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './Composer-ABGJIAIR.css';
5
5
  import { forwardRef } from 'react';
@@ -1,5 +1,6 @@
1
+ import { FormField } from './chunk-4GB57WIT.js';
1
2
  import { cx } from './chunk-ODEQTPFM.js';
2
- import './Checkbox-UE7TEPAM.css';
3
+ import './Checkbox-KT7RS6QQ.css';
3
4
  import { forwardRef, useId, useRef, useCallback, useEffect } from 'react';
4
5
  import { jsxs, jsx } from 'react/jsx-runtime';
5
6
 
@@ -70,5 +71,14 @@ var Checkbox = forwardRef(function Checkbox2({
70
71
  }
71
72
  );
72
73
  });
74
+ function hasChildren(children) {
75
+ if (children === null || children === void 0 || children === false) return false;
76
+ if (Array.isArray(children)) return children.some(hasChildren);
77
+ return true;
78
+ }
79
+ function CheckboxGroup({ legend, helper, error, emptyMessage, children, className }) {
80
+ const empty = !hasChildren(children);
81
+ return /* @__PURE__ */ jsx(FormField, { as: "fieldset", label: legend, helper, error, className: cx("crewlet-checkbox-group", className), children: empty ? emptyMessage ? /* @__PURE__ */ jsx("p", { className: "crewlet-checkbox-group__empty", children: emptyMessage }) : null : /* @__PURE__ */ jsx("div", { className: "crewlet-checkbox-group__options", children }) });
82
+ }
73
83
 
74
- export { Checkbox };
84
+ export { Checkbox, CheckboxGroup };
@@ -0,0 +1,37 @@
1
+ import { BrandLockup } from './chunk-7KBNFFM3.js';
2
+ import { Card } from './chunk-EG6NYWVK.js';
3
+ import { cx } from './chunk-ODEQTPFM.js';
4
+ import './AuthLayout-ODHBUPHQ.css';
5
+ import { useId } from 'react';
6
+ import { CrewletIcon } from '@crewlethq/icons';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ function AuthLayout({
10
+ title,
11
+ description,
12
+ productName = "Crewlet",
13
+ mark,
14
+ homeHref,
15
+ children,
16
+ className
17
+ }) {
18
+ const heading = useId();
19
+ return /* @__PURE__ */ jsx("main", { className: cx("crewlet-auth-layout", className), children: /* @__PURE__ */ jsxs("div", { className: "crewlet-auth-layout__column", children: [
20
+ /* @__PURE__ */ jsx(
21
+ BrandLockup,
22
+ {
23
+ className: "crewlet-auth-layout__brand",
24
+ name: productName,
25
+ mark: mark ?? /* @__PURE__ */ jsx(CrewletIcon, {}),
26
+ href: homeHref
27
+ }
28
+ ),
29
+ /* @__PURE__ */ jsxs(Card, { as: "section", padding: "lg", "aria-labelledby": heading, children: [
30
+ /* @__PURE__ */ jsx(Card.Title, { as: "h1", id: heading, children: title }),
31
+ description ? /* @__PURE__ */ jsx(Card.Description, { children: description }) : null,
32
+ children === void 0 || children === null || children === false ? null : /* @__PURE__ */ jsx("div", { className: "crewlet-auth-layout__body", children })
33
+ ] })
34
+ ] }) });
35
+ }
36
+
37
+ export { AuthLayout };
@@ -0,0 +1,53 @@
1
+ import { useDownload, safeFilename } from './chunk-F6NZOVWL.js';
2
+ import { Button } from './chunk-OG6CL3EB.js';
3
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
+ import { useMemo, useCallback } from 'react';
5
+ import { CheckGlyph, CircleAlertGlyph, SaveGlyph } from '@crewlethq/icons/glyphs';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ function downloadGlyph(state) {
9
+ if (state === "started") return /* @__PURE__ */ jsx(CheckGlyph, { size: "sm" });
10
+ if (state === "failed") return /* @__PURE__ */ jsx(CircleAlertGlyph, { size: "sm" });
11
+ return /* @__PURE__ */ jsx(SaveGlyph, { size: "sm" });
12
+ }
13
+ function DownloadButton({
14
+ text,
15
+ filename,
16
+ mime,
17
+ label = "Download",
18
+ startedLabel = "Downloading",
19
+ failedLabel = "Download failed",
20
+ startedMessage,
21
+ failedMessage = "the browser refused the download",
22
+ size = "small",
23
+ variant = "ghost",
24
+ title,
25
+ disabled,
26
+ resetMs,
27
+ failedResetMs = null,
28
+ className
29
+ }) {
30
+ const { state, attempt, download } = useDownload({ resetMs, failedResetMs });
31
+ const name = useMemo(() => safeFilename(filename), [filename]);
32
+ const onClick = useCallback(() => {
33
+ void download(text, filename, mime);
34
+ }, [download, text, filename, mime]);
35
+ const said = state === "started" ? startedMessage ?? `download started: ${name}` : state === "failed" ? failedMessage : "";
36
+ return /* @__PURE__ */ jsxs("span", { className, children: [
37
+ /* @__PURE__ */ jsx(
38
+ Button,
39
+ {
40
+ size,
41
+ variant,
42
+ leadingIcon: downloadGlyph(state),
43
+ onClick,
44
+ disabled,
45
+ title: state === "failed" ? failedMessage : title,
46
+ children: state === "started" ? startedLabel : state === "failed" ? failedLabel : label
47
+ }
48
+ ),
49
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx("span", { role: "status", children: /* @__PURE__ */ jsx("span", { children: said }, attempt) }) })
50
+ ] });
51
+ }
52
+
53
+ export { DownloadButton };
@@ -1,4 +1,4 @@
1
- import { OrgLabel } from './chunk-22M7OXKW.js';
1
+ import { OrgLabel } from './chunk-6DQWF5Y4.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './OrgNode-TCHJH5FO.css';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Avatar } from './chunk-HI6Q2UXQ.js';
1
+ import { Avatar } from './chunk-FY4SP3HF.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './EntityChip-LUCPZBBG.css';
4
4
  import { Children, isValidElement, cloneElement } from 'react';
@@ -0,0 +1,39 @@
1
+ import { InlineCode } from './chunk-5CLW2CXT.js';
2
+ import { FormField, Input } from './chunk-4GB57WIT.js';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+
5
+ function confirmMatches(typed, phrase) {
6
+ return phrase !== "" && typed.trim() === phrase;
7
+ }
8
+ var defaultLabel = (phrase) => /* @__PURE__ */ jsxs(Fragment, { children: [
9
+ "Type ",
10
+ phrase,
11
+ " to confirm"
12
+ ] });
13
+ function ConfirmField({
14
+ phrase,
15
+ value,
16
+ onValueChange,
17
+ label = defaultLabel,
18
+ helper,
19
+ autoFocus,
20
+ className
21
+ }) {
22
+ return /* @__PURE__ */ jsx(FormField, { label: label(/* @__PURE__ */ jsx(InlineCode, { children: phrase })), helper, className, children: (field) => /* @__PURE__ */ jsx(
23
+ Input,
24
+ {
25
+ id: field.id,
26
+ "aria-describedby": field.describedBy,
27
+ autoFocus,
28
+ width: "full",
29
+ spellCheck: false,
30
+ autoComplete: "off",
31
+ autoCapitalize: "none",
32
+ autoCorrect: "off",
33
+ value,
34
+ onChange: (event) => onValueChange(event.target.value)
35
+ }
36
+ ) });
37
+ }
38
+
39
+ export { ConfirmField, confirmMatches };
@@ -0,0 +1,37 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
2
+
3
+ // src/utils/useOutcome.ts
4
+ function useOutcome({ resetMs = 2e3, failedResetMs } = {}) {
5
+ const [{ state, attempt }, setOutcome] = useState({
6
+ state: "idle",
7
+ attempt: 0
8
+ });
9
+ const timer = useRef(void 0);
10
+ const live = useRef(true);
11
+ useEffect(() => {
12
+ live.current = true;
13
+ return () => {
14
+ live.current = false;
15
+ clearTimeout(timer.current);
16
+ timer.current = void 0;
17
+ };
18
+ }, []);
19
+ const run = useCallback(
20
+ async (task) => {
21
+ const ok = await task();
22
+ if (!live.current) return ok;
23
+ setOutcome((prior) => ({ state: ok ? "done" : "failed", attempt: prior.attempt + 1 }));
24
+ clearTimeout(timer.current);
25
+ timer.current = void 0;
26
+ const after = ok ? resetMs : failedResetMs === void 0 ? resetMs : failedResetMs;
27
+ if (after !== null) {
28
+ timer.current = setTimeout(() => setOutcome((prior) => ({ ...prior, state: "idle" })), after);
29
+ }
30
+ return ok;
31
+ },
32
+ [resetMs, failedResetMs]
33
+ );
34
+ return { state, attempt, run };
35
+ }
36
+
37
+ export { useOutcome };
@@ -1,5 +1,5 @@
1
1
  import { useRoving, tabStop } from './chunk-CBOICT64.js';
2
- import { Avatar } from './chunk-HI6Q2UXQ.js';
2
+ import { Avatar } from './chunk-FY4SP3HF.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY } from '@crewlethq/icons/characters';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,11 +1,11 @@
1
1
  import { Menu } from './chunk-NS7BVLL3.js';
2
2
  import { EmptyValue } from './chunk-EUCC37WY.js';
3
- import { Checkbox } from './chunk-YCTMKKRA.js';
4
- import { useClipboard } from './chunk-5VNUYO76.js';
5
- import { Modal } from './chunk-K4VORB64.js';
3
+ import { Modal } from './chunk-DEEVA6TV.js';
4
+ import { Checkbox } from './chunk-75CLJNDQ.js';
5
+ import { useClipboard } from './chunk-STJ7QBC3.js';
6
6
  import { Button } from './chunk-OG6CL3EB.js';
7
- import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
8
7
  import { IconButton } from './chunk-4FQT6ZAY.js';
8
+ import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
9
9
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
10
10
  import { cx } from './chunk-ODEQTPFM.js';
11
11
  import './DataTable-WZK3V62B.css';
@@ -0,0 +1,68 @@
1
+ import { useOutcome } from './chunk-DTIW4CHZ.js';
2
+ import { useCallback } from 'react';
3
+
4
+ var DEFAULT_MIME = "text/plain;charset=utf-8";
5
+ function useDownload(options = {}) {
6
+ const outcome = useOutcome(options);
7
+ const { run } = outcome;
8
+ const download = useCallback(
9
+ (text, filename, mime = DEFAULT_MIME) => run(() => downloadText(typeof text === "function" ? text() : text, filename, mime).started),
10
+ [run]
11
+ );
12
+ const state = outcome.state === "done" ? "started" : outcome.state;
13
+ return { state, attempt: outcome.attempt, download };
14
+ }
15
+ function downloadText(text, filename, mime = DEFAULT_MIME) {
16
+ const name = safeFilename(filename);
17
+ if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function" || typeof HTMLAnchorElement === "undefined" || !("download" in HTMLAnchorElement.prototype)) {
18
+ return { started: false, name };
19
+ }
20
+ let url = "";
21
+ try {
22
+ url = URL.createObjectURL(new Blob([text], { type: mime }));
23
+ const link = document.createElement("a");
24
+ link.href = url;
25
+ link.download = name;
26
+ document.body.appendChild(link);
27
+ try {
28
+ link.click();
29
+ } finally {
30
+ link.remove();
31
+ }
32
+ return { started: true, name };
33
+ } catch {
34
+ return { started: false, name };
35
+ } finally {
36
+ if (url) setTimeout(() => URL.revokeObjectURL(url), 0);
37
+ }
38
+ }
39
+ var MAX_EXTENSION = 12;
40
+ var MAX_FILENAME = 120;
41
+ var encoder = new TextEncoder();
42
+ function bytes(value) {
43
+ return encoder.encode(value).length;
44
+ }
45
+ function cutToBytes(value, max) {
46
+ if (max <= 0) return "";
47
+ if (bytes(value) <= max) return value;
48
+ let out = "";
49
+ let used = 0;
50
+ for (const character of value) {
51
+ const size = bytes(character);
52
+ if (used + size > max) break;
53
+ out += character;
54
+ used += size;
55
+ }
56
+ return out;
57
+ }
58
+ function safeFilename(name) {
59
+ const cleaned = name.replace(/[^\p{L}\p{M}\p{N}_.-]+/gu, "-").replace(/-{2,}/g, "-");
60
+ const dot = cleaned.lastIndexOf(".");
61
+ const tail = cleaned.length - dot;
62
+ const extension = dot >= 0 && tail >= 2 && tail <= MAX_EXTENSION ? cleaned.slice(dot) : "";
63
+ const stem = (extension ? cleaned.slice(0, dot) : cleaned).replace(/^[-.]+/, "");
64
+ if (!stem) return `download${extension}`;
65
+ return cutToBytes(stem, MAX_FILENAME - bytes(extension)) + extension;
66
+ }
67
+
68
+ export { downloadText, safeFilename, useDownload };
@@ -1,7 +1,7 @@
1
1
  import { Skeleton } from './chunk-W5J7R5EB.js';
2
- import { Modal } from './chunk-K4VORB64.js';
2
+ import { Modal } from './chunk-DEEVA6TV.js';
3
3
  import { useListbox, useOptionKeys } from './chunk-F73MC7EZ.js';
4
- import { Input } from './chunk-FTEJPHBI.js';
4
+ import { Input } from './chunk-4GB57WIT.js';
5
5
  import { KeyChip, highlightMatch } from './chunk-FYTIJM2T.js';
6
6
  import { announce } from './chunk-RSAQOKH3.js';
7
7
  import { useMediaMatch } from './chunk-IG75YMUN.js';
@@ -1,8 +1,8 @@
1
1
  import { HuePicker } from './chunk-NXDEPUVG.js';
2
2
  import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
3
3
  import { Popover } from './chunk-BWRGFKJP.js';
4
- import { CharacterPicker } from './chunk-YXMCUKFI.js';
5
- import { Avatar } from './chunk-HI6Q2UXQ.js';
4
+ import { CharacterPicker } from './chunk-DZ2YR6MV.js';
5
+ import { Avatar } from './chunk-FY4SP3HF.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './AvatarPicker-PREY36MG.css';
8
8
  import { CREWLET_CHARACTER_GEOMETRY, CREWLET_CHARACTERS } from '@crewlethq/icons/characters';
@@ -11,6 +11,12 @@ var AVATAR_STATUS_LABELS = {
11
11
  };
12
12
  var AVATAR_SIZES = { xs: 20, sm: 26, md: 32, lg: 40 };
13
13
  var AVATAR_CORNER_RATIO = 0.29;
14
+ var AGENT_WORD = /^agent(?:[\s._-]+)(?=\S)/i;
15
+ function avatarInitialsName(name, kind) {
16
+ if (name === void 0 || kind !== "agent") return name;
17
+ const rest = name.replace(AGENT_WORD, "");
18
+ return rest.trim() ? rest : name;
19
+ }
14
20
  var AVATAR_CHARACTER_FULL_DETAIL = 56;
15
21
  var getInitials = (name) => {
16
22
  if (!name) return "?";
@@ -49,6 +55,7 @@ var Avatar = ({
49
55
  colorSeed,
50
56
  character,
51
57
  hue,
58
+ icon,
52
59
  className,
53
60
  style,
54
61
  ...rest
@@ -124,13 +131,14 @@ var Avatar = ({
124
131
  classes,
125
132
  "crewlet-avatar--fallback",
126
133
  `crewlet-avatar--${tone}`,
127
- seeded === null ? null : `crewlet-avatar--tint-${seeded}`
134
+ seeded === null ? null : `crewlet-avatar--tint-${seeded}`,
135
+ icon === void 0 || icon === null ? null : "crewlet-avatar--icon"
128
136
  ),
129
137
  style: faceStyle,
130
138
  role: decorative ? void 0 : "img",
131
139
  "aria-hidden": decorative ? true : void 0,
132
140
  "aria-label": decorative ? void 0 : spoken,
133
- children: getInitials(name)
141
+ children: icon === void 0 || icon === null ? getInitials(avatarInitialsName(name, kind)) : /* @__PURE__ */ jsx("span", { className: "crewlet-avatar__icon", "aria-hidden": "true", children: icon })
134
142
  }
135
143
  );
136
144
  }
@@ -166,4 +174,4 @@ var STATUS_GLYPHS = {
166
174
  stopped: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 14 14", focusable: "false", children: /* @__PURE__ */ jsx("rect", { x: "4.6", y: "4.6", width: "4.8", height: "4.8", rx: ".7", fill: "currentColor" }) })
167
175
  };
168
176
 
169
- export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, AVATAR_STATUSES, AVATAR_STATUS_LABELS, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials };
177
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, AVATAR_STATUSES, AVATAR_STATUS_LABELS, Avatar, avatarCorner, avatarInitialsName, avatarPixels, avatarTint, getInitials };
@@ -1,4 +1,4 @@
1
- import { CopyButton } from './chunk-YACKC3K2.js';
1
+ import { CopyButton } from './chunk-W46LPU4R.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './CodeBlock-GYNJ2HI6.css';
4
4
  import { forwardRef, useRef, useState, useLayoutEffect } from 'react';