@lostgradient/cinder 0.9.0 → 0.12.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 (169) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/components.json +82 -4
  3. package/dist/components/access-gate/index.js +381 -239
  4. package/dist/components/chat/builders.d.ts +17 -8
  5. package/dist/components/chat/conversation-model.d.ts +1 -1
  6. package/dist/components/chat/index.d.ts +1 -1
  7. package/dist/components/chat/index.js +300 -17
  8. package/dist/components/chat/utilities/conversation.d.ts +6 -6
  9. package/dist/components/chat-conversation-header/index.js +19 -6
  10. package/dist/components/chat-conversation-list/index.js +19 -6
  11. package/dist/components/code-block/code-block.css +15 -9
  12. package/dist/components/code-block/code-block.variables.js +8 -2
  13. package/dist/components/confirm-dialog/confirm-dialog.css +2 -0
  14. package/dist/components/confirm-dialog/confirm-dialog.schema.js +10 -1
  15. package/dist/components/confirm-dialog/confirm-dialog.types.d.ts +7 -0
  16. package/dist/components/confirm-dialog/index.js +478 -106
  17. package/dist/components/connection-indicator/connection-indicator.css +136 -0
  18. package/dist/components/connection-indicator/connection-indicator.css.d.ts +1 -0
  19. package/dist/components/connection-indicator/connection-indicator.schema.d.ts +3 -0
  20. package/dist/components/connection-indicator/connection-indicator.schema.js +89 -0
  21. package/dist/components/connection-indicator/connection-indicator.svelte.d.ts +21 -0
  22. package/dist/components/connection-indicator/connection-indicator.types.d.ts +46 -0
  23. package/dist/components/connection-indicator/connection-indicator.variables.d.ts +2 -0
  24. package/dist/components/connection-indicator/connection-indicator.variables.js +61 -0
  25. package/dist/components/connection-indicator/index.d.ts +5 -0
  26. package/dist/components/connection-indicator/index.js +409 -0
  27. package/dist/components/container/container.schema.js +4 -4
  28. package/dist/components/faceted-filter-bar/faceted-filter-bar.schema.js +5 -1
  29. package/dist/components/faceted-filter-bar/faceted-filter-bar.types.d.ts +2 -0
  30. package/dist/components/faceted-filter-bar/index.js +40 -31
  31. package/dist/components/invocation-rule-builder/index.d.ts +1 -1
  32. package/dist/components/invocation-rule-builder/index.js +305 -150
  33. package/dist/components/invocation-rule-builder/invocation-rule-builder.css +28 -0
  34. package/dist/components/invocation-rule-builder/invocation-rule-builder.schema.js +89 -5
  35. package/dist/components/invocation-rule-builder/invocation-rule-builder.svelte.d.ts +2 -1
  36. package/dist/components/invocation-rule-builder/invocation-rule-builder.types.d.ts +114 -16
  37. package/dist/components/navigation-bar/index.js +11 -17
  38. package/dist/components/run-step-timeline/index.d.ts +1 -1
  39. package/dist/components/run-step-timeline/index.js +1052 -560
  40. package/dist/components/run-step-timeline/run-step-branch-disclosure.svelte.d.ts +17 -0
  41. package/dist/components/run-step-timeline/run-step-timeline.css +124 -0
  42. package/dist/components/run-step-timeline/run-step-timeline.schema.js +873 -350
  43. package/dist/components/run-step-timeline/run-step-timeline.svelte.d.ts +1 -15
  44. package/dist/components/run-step-timeline/run-step-timeline.types.d.ts +182 -5
  45. package/dist/components/run-step-timeline/run-step-timeline.utilities.d.ts +60 -0
  46. package/dist/components/schedule-builder/index.d.ts +5 -0
  47. package/dist/components/schedule-builder/index.js +3176 -0
  48. package/dist/components/schedule-builder/schedule-builder.css +121 -0
  49. package/dist/components/schedule-builder/schedule-builder.css.d.ts +1 -0
  50. package/dist/components/schedule-builder/schedule-builder.schema.d.ts +3 -0
  51. package/dist/components/schedule-builder/schedule-builder.schema.js +141 -0
  52. package/dist/components/schedule-builder/schedule-builder.svelte.d.ts +22 -0
  53. package/dist/components/schedule-builder/schedule-builder.types.d.ts +130 -0
  54. package/dist/components/schedule-builder/schedule-builder.utilities.d.ts +78 -0
  55. package/dist/components/schedule-builder/schedule-builder.variables.d.ts +2 -0
  56. package/dist/components/schedule-builder/schedule-builder.variables.js +61 -0
  57. package/dist/components/tag-input/index.js +22 -4
  58. package/dist/components/tag-input/tag-input.schema.js +5 -1
  59. package/dist/components/tag-input/tag-input.types.d.ts +4 -0
  60. package/dist/index.d.ts +6 -2
  61. package/dist/index.js +23069 -20833
  62. package/dist/server/components/access-gate/index.js +2 -1
  63. package/dist/server/components/chat/index.js +4 -4
  64. package/dist/server/components/chat-conversation-header/index.js +5 -5
  65. package/dist/server/components/chat-conversation-list/index.js +3 -3
  66. package/dist/server/components/color-field/index.js +2 -2
  67. package/dist/server/components/confirm-dialog/index.js +7 -2
  68. package/dist/server/components/connection-indicator/index.js +16 -0
  69. package/dist/server/components/data-table/index.js +3 -3
  70. package/dist/server/components/diff-viewer/index.js +4 -3
  71. package/dist/server/components/faceted-filter-bar/index.js +1 -1
  72. package/dist/server/components/invocation-rule-builder/index.js +1 -1
  73. package/dist/server/components/json-schema-editor/index.js +4 -3
  74. package/dist/server/components/navigation-bar/index.js +1 -1
  75. package/dist/server/components/review-editor/index.js +4 -3
  76. package/dist/server/components/run-step-timeline/index.js +1 -1
  77. package/dist/server/components/schedule-builder/index.js +30 -0
  78. package/dist/server/components/side-navigation/index.js +2 -2
  79. package/dist/server/components/table/index.js +3 -3
  80. package/dist/server/components/tag-input/index.js +1 -1
  81. package/dist/server/components/time-field/index.js +5 -3
  82. package/dist/server/index.js +105 -92
  83. package/dist/server/index.server-0sx92swg.js +9 -0
  84. package/dist/server/{index.server-mzzb7dnm.js → index.server-2bbwajb2.js} +1 -1
  85. package/dist/server/{index.server-q7w4jw89.js → index.server-2s5h1d05.js} +2 -2
  86. package/dist/server/{index.server-dg83ke3k.js → index.server-2zdbz3rj.js} +1 -1
  87. package/dist/server/{index.server-0jhra85x.js → index.server-3w72dxz7.js} +4 -4
  88. package/dist/server/{index.server-5tf22d6e.js → index.server-4wx0qven.js} +3 -3
  89. package/dist/server/{index.server-qh9qzd5t.js → index.server-4x4hgvqe.js} +283 -13
  90. package/dist/server/{index.server-c6pe4kaf.js → index.server-5gzyqv78.js} +1 -1
  91. package/dist/server/{index.server-mqt1ngqw.js → index.server-6hnfzc7f.js} +19 -6
  92. package/dist/server/{index.server-894t97kv.js → index.server-7yvpb6z7.js} +4 -4
  93. package/dist/server/index.server-be9bpqeh.js +93 -0
  94. package/dist/server/{index.server-f3z7tpxr.js → index.server-c42b462p.js} +2 -4
  95. package/dist/server/{index.server-7vyzen5x.js → index.server-c5qv3p61.js} +171 -63
  96. package/dist/server/index.server-cch0eed5.js +144 -0
  97. package/dist/server/{index.server-btgb3d56.js → index.server-d5a5ccz7.js} +18 -12
  98. package/dist/server/index.server-g5jgq3jp.js +793 -0
  99. package/dist/server/index.server-gmh5ar16.js +2 -0
  100. package/dist/server/{index.server-0atyznp7.js → index.server-h89zk5ev.js} +7 -7
  101. package/dist/server/{index.server-jxg42jpz.js → index.server-jdcq5zza.js} +7 -7
  102. package/dist/server/{index.server-2dga5yzr.js → index.server-jfrssta6.js} +1 -1
  103. package/dist/server/{index.server-fy068yne.js → index.server-jj76374p.js} +1 -1
  104. package/dist/server/{index.server-39ne5cd1.js → index.server-pxq277t5.js} +32 -1
  105. package/dist/server/index.server-qbkxz7r2.js +750 -0
  106. package/dist/server/{index.server-marjz8ps.js → index.server-tcay903b.js} +3 -2
  107. package/dist/server/{index.server-yz4k36cw.js → index.server-z7hxtqs1.js} +1 -1
  108. package/package.json +87 -97
  109. package/src/components/chat/builders.ts +445 -14
  110. package/src/components/chat/conversation-model.ts +1 -0
  111. package/src/components/chat/index.ts +1 -0
  112. package/src/components/chat/utilities/conversation.ts +33 -15
  113. package/src/components/code-block/code-block.css +15 -9
  114. package/src/components/code-block/code-block.variables.json +7 -1
  115. package/src/components/code-block/code-block.variables.ts +7 -1
  116. package/src/components/confirm-dialog/confirm-dialog.css +2 -0
  117. package/src/components/confirm-dialog/confirm-dialog.schema.json +8 -0
  118. package/src/components/confirm-dialog/confirm-dialog.schema.ts +10 -0
  119. package/src/components/confirm-dialog/confirm-dialog.svelte +31 -3
  120. package/src/components/confirm-dialog/confirm-dialog.types.ts +7 -0
  121. package/src/components/connection-indicator/connection-indicator.css +136 -0
  122. package/src/components/connection-indicator/connection-indicator.examples.json +31 -0
  123. package/src/components/connection-indicator/connection-indicator.schema.json +29 -0
  124. package/src/components/connection-indicator/connection-indicator.schema.ts +36 -0
  125. package/src/components/connection-indicator/connection-indicator.svelte +63 -0
  126. package/src/components/connection-indicator/connection-indicator.types.ts +58 -0
  127. package/src/components/connection-indicator/connection-indicator.variables.json +1 -0
  128. package/src/components/connection-indicator/connection-indicator.variables.ts +3 -0
  129. package/src/components/connection-indicator/index.ts +10 -0
  130. package/src/components/container/container.schema.json +3 -3
  131. package/src/components/container/container.schema.ts +3 -3
  132. package/src/components/faceted-filter-bar/faceted-filter-bar.schema.json +4 -0
  133. package/src/components/faceted-filter-bar/faceted-filter-bar.schema.ts +4 -0
  134. package/src/components/faceted-filter-bar/faceted-filter-bar.svelte +13 -11
  135. package/src/components/faceted-filter-bar/faceted-filter-bar.types.ts +2 -0
  136. package/src/components/invocation-rule-builder/index.ts +4 -0
  137. package/src/components/invocation-rule-builder/invocation-rule-builder.css +28 -0
  138. package/src/components/invocation-rule-builder/invocation-rule-builder.examples.json +6 -0
  139. package/src/components/invocation-rule-builder/invocation-rule-builder.schema.json +76 -3
  140. package/src/components/invocation-rule-builder/invocation-rule-builder.schema.ts +83 -3
  141. package/src/components/invocation-rule-builder/invocation-rule-builder.svelte +326 -113
  142. package/src/components/invocation-rule-builder/invocation-rule-builder.types.ts +157 -43
  143. package/src/components/navigation-bar/navigation-bar.svelte +2 -2
  144. package/src/components/run-step-timeline/index.ts +8 -0
  145. package/src/components/run-step-timeline/run-step-branch-disclosure.svelte +16 -0
  146. package/src/components/run-step-timeline/run-step-timeline.css +124 -0
  147. package/src/components/run-step-timeline/run-step-timeline.examples.json +18 -0
  148. package/src/components/run-step-timeline/run-step-timeline.schema.json +872 -349
  149. package/src/components/run-step-timeline/run-step-timeline.schema.ts +931 -349
  150. package/src/components/run-step-timeline/run-step-timeline.svelte +388 -269
  151. package/src/components/run-step-timeline/run-step-timeline.types.ts +192 -5
  152. package/src/components/run-step-timeline/run-step-timeline.utilities.ts +310 -0
  153. package/src/components/schedule-builder/index.ts +14 -0
  154. package/src/components/schedule-builder/schedule-builder.css +121 -0
  155. package/src/components/schedule-builder/schedule-builder.examples.json +31 -0
  156. package/src/components/schedule-builder/schedule-builder.schema.json +78 -0
  157. package/src/components/schedule-builder/schedule-builder.schema.ts +86 -0
  158. package/src/components/schedule-builder/schedule-builder.svelte +629 -0
  159. package/src/components/schedule-builder/schedule-builder.types.ts +137 -0
  160. package/src/components/schedule-builder/schedule-builder.utilities.ts +344 -0
  161. package/src/components/schedule-builder/schedule-builder.variables.json +1 -0
  162. package/src/components/schedule-builder/schedule-builder.variables.ts +3 -0
  163. package/src/components/tag-input/tag-input.schema.json +4 -0
  164. package/src/components/tag-input/tag-input.schema.ts +4 -0
  165. package/src/components/tag-input/tag-input.svelte +20 -3
  166. package/src/components/tag-input/tag-input.types.ts +4 -0
  167. package/src/index.ts +23 -0
  168. package/src/styles/components.css +2 -0
  169. package/dist/server/index.server-qk1h0n02.js +0 -393
@@ -4,11 +4,25 @@ export {};
4
4
 
5
5
  <script lang="ts">
6
6
  import Button from '../button/button.svelte';
7
+ import Input from '../input/input.svelte';
7
8
  import Modal from '../modal/modal.svelte';
8
9
  import { classNames } from '../../utilities/class-names.ts';
9
10
  const descriptionId = $props.id();
10
- let { open = $bindable(false), title, description, cancelLabel = 'Cancel', confirmLabel, destructive = false, onconfirm, oncancel, triggerRef = null, class: className, } = $props();
11
+ const typedConfirmationId = `${descriptionId}-typed-confirmation`;
12
+ let { open = $bindable(false), title, description, cancelLabel = 'Cancel', confirmLabel, destructive = false, typeToConfirm, typeToConfirmLabel, onconfirm, oncancel, triggerRef = null, class: className, } = $props();
11
13
  const describedById = $derived(description ? descriptionId : undefined);
14
+ const normalizedTypeToConfirm = $derived(typeToConfirm?.trim() || undefined);
15
+ const normalizedTypeToConfirmLabel = $derived(typeToConfirmLabel?.trim() || undefined);
16
+ let typedConfirmation = $state('');
17
+ let previousOpen = open;
18
+ const typedConfirmationMatches = $derived(normalizedTypeToConfirm === undefined ||
19
+ typedConfirmation.trim().toLowerCase() === normalizedTypeToConfirm.toLowerCase());
20
+ $effect(() => {
21
+ if (open === previousOpen)
22
+ return;
23
+ previousOpen = open;
24
+ typedConfirmation = '';
25
+ });
12
26
  function handleCancel() {
13
27
  // Mirror Modal's dismiss() ordering: state first, then callback. No try/catch —
14
28
  // consumer errors must propagate so tests, error boundaries, and observability see them.
@@ -34,10 +48,24 @@ function handleConfirm() {
34
48
  <p id={descriptionId} class="cinder-confirm-dialog__description">{description}</p>
35
49
  {/if}
36
50
 
51
+ {#if normalizedTypeToConfirm !== undefined}
52
+ <Input
53
+ id={typedConfirmationId}
54
+ class="cinder-confirm-dialog__typed-confirmation"
55
+ bind:value={typedConfirmation}
56
+ label={normalizedTypeToConfirmLabel ?? `Type "${normalizedTypeToConfirm}" to confirm`}
57
+ autocomplete="off"
58
+ />
59
+ {/if}
60
+
37
61
  {#snippet footer()}
38
62
  <Button variant="secondary" autofocus onclick={handleCancel}>{cancelLabel}</Button>
39
- <Button variant={destructive ? 'danger' : 'primary'} onclick={handleConfirm}
40
- >{confirmLabel}</Button
63
+ <Button
64
+ variant={destructive ? 'danger' : 'primary'}
65
+ disabled={!typedConfirmationMatches}
66
+ onclick={handleConfirm}
41
67
  >
68
+ {confirmLabel}
69
+ </Button>
42
70
  {/snippet}
43
71
  </Modal>
@@ -36,6 +36,13 @@ export type ConfirmDialogProps = {
36
36
  * receives default focus regardless — color is never the sole destructive signal.
37
37
  */
38
38
  destructive?: boolean;
39
+ /**
40
+ * When set, renders a labelled text input and disables the confirm button until the
41
+ * trimmed input matches this value case-insensitively.
42
+ */
43
+ typeToConfirm?: string;
44
+ /** Visible label for the typed-confirmation input. Defaults to `Type "<value>" to confirm`. */
45
+ typeToConfirmLabel?: string;
39
46
  /** Fired when the user activates the confirm button. Required. Component closes itself after. */
40
47
  onconfirm: () => void;
41
48
  /**
@@ -0,0 +1,136 @@
1
+ @layer cinder.tokens, cinder.foundation, cinder.components, cinder.utilities;
2
+ @layer cinder.components {
3
+ /* ========================================
4
+ * CONNECTION INDICATOR
5
+ *
6
+ * Small standalone status pill for a live connection. Color is driven
7
+ * exclusively from the `data-cinder-status` attribute via the existing
8
+ * semantic status tokens (`--cinder-success`, `--cinder-warning`,
9
+ * `--cinder-text-muted`) — never hard-code hex values when consuming this
10
+ * component. `polling` is deliberately quieter than `live`: it carries no
11
+ * motion and a lighter font-weight so it can never be mistaken for push,
12
+ * even under grayscale or forced-colors rendering where the color
13
+ * difference disappears.
14
+ * ======================================== */
15
+
16
+ .cinder-connection-indicator {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ gap: var(--cinder-space-1-5);
20
+ padding: var(--cinder-space-0-5) var(--cinder-space-2-5);
21
+ border-radius: var(--cinder-radius-full);
22
+ background: var(--cinder-surface-inset);
23
+ color: var(--cinder-text-muted);
24
+ font-size: var(--cinder-text-xs);
25
+ font-weight: var(--cinder-font-medium);
26
+ line-height: 1.25;
27
+ vertical-align: middle;
28
+ }
29
+
30
+ .cinder-connection-indicator__dot {
31
+ display: inline-block;
32
+ flex-shrink: 0;
33
+ inline-size: 0.375rem;
34
+ block-size: 0.375rem;
35
+ border-radius: var(--cinder-radius-full);
36
+ background: currentColor;
37
+ }
38
+
39
+ .cinder-connection-indicator[data-cinder-status='live'] .cinder-connection-indicator__dot {
40
+ animation: cinder-connection-indicator-pulse 1.4s ease-in-out infinite;
41
+ }
42
+
43
+ @media (prefers-reduced-motion: reduce) {
44
+ .cinder-connection-indicator[data-cinder-status='live'] .cinder-connection-indicator__dot {
45
+ animation: none;
46
+ }
47
+ }
48
+
49
+ @keyframes cinder-connection-indicator-pulse {
50
+ 0%,
51
+ 100% {
52
+ opacity: 1;
53
+ }
54
+ 50% {
55
+ opacity: 0.35;
56
+ }
57
+ }
58
+
59
+ .cinder-connection-indicator__icon {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ flex-shrink: 0;
64
+ inline-size: 0.8125rem;
65
+ block-size: 0.8125rem;
66
+ color: currentColor;
67
+ }
68
+
69
+ /* connecting and reconnecting both spin the icon wrapper to signal in-progress work. This
70
+ * targets the wrapper span (not the inner svg with a :global() selector) because this file is
71
+ * a plain CSS asset imported from index.ts — the Svelte compiler never processes it, so
72
+ * :global() has no effect here and browsers drop the whole rule as an unknown pseudo-class.
73
+ * Rotating the wrapper rotates its svg child identically. */
74
+ .cinder-connection-indicator[data-cinder-status='connecting'] .cinder-connection-indicator__icon,
75
+ .cinder-connection-indicator[data-cinder-status='reconnecting']
76
+ .cinder-connection-indicator__icon {
77
+ animation: cinder-connection-indicator-spin var(--cinder-duration-spin) linear infinite;
78
+ }
79
+
80
+ @media (prefers-reduced-motion: reduce) {
81
+ .cinder-connection-indicator[data-cinder-status='connecting']
82
+ .cinder-connection-indicator__icon,
83
+ .cinder-connection-indicator[data-cinder-status='reconnecting']
84
+ .cinder-connection-indicator__icon {
85
+ animation: none;
86
+ }
87
+ }
88
+
89
+ @keyframes cinder-connection-indicator-spin {
90
+ to {
91
+ transform: rotate(360deg);
92
+ }
93
+ }
94
+
95
+ .cinder-connection-indicator__label {
96
+ color: inherit;
97
+ }
98
+
99
+ .cinder-connection-indicator__attempt {
100
+ color: var(--cinder-text-muted);
101
+ font-weight: var(--cinder-font-normal);
102
+ }
103
+
104
+ /* ----------------------------------------
105
+ * Status → semantic token mapping
106
+ *
107
+ * `polling` reuses the same muted tone as `closed` but is disambiguated by
108
+ * its icon, its lack of motion (see above), and its label text — color is
109
+ * never the sole signal (WCAG 1.4.1).
110
+ * ---------------------------------------- */
111
+
112
+ .cinder-connection-indicator[data-cinder-status='connecting'] {
113
+ color: var(--cinder-warning);
114
+ }
115
+
116
+ .cinder-connection-indicator[data-cinder-status='live'] {
117
+ color: var(--cinder-success);
118
+ }
119
+
120
+ .cinder-connection-indicator[data-cinder-status='reconnecting'] {
121
+ color: var(--cinder-warning);
122
+ }
123
+
124
+ .cinder-connection-indicator[data-cinder-status='polling'] {
125
+ color: var(--cinder-text-muted);
126
+ font-weight: var(--cinder-font-normal);
127
+ }
128
+
129
+ .cinder-connection-indicator[data-cinder-status='stale'] {
130
+ color: var(--cinder-info);
131
+ }
132
+
133
+ .cinder-connection-indicator[data-cinder-status='closed'] {
134
+ color: var(--cinder-text-muted);
135
+ }
136
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "../../schemas/examples.schema.json",
3
+ "component": "connection-indicator",
4
+ "import": "@lostgradient/cinder/connection-indicator",
5
+ "examples": [
6
+ {
7
+ "id": "basic",
8
+ "title": "Basic connection indicator",
9
+ "description": "A live connection pill with its default icon and label.",
10
+ "code": "<script lang=\"ts\">\n import { ConnectionIndicator } from '@lostgradient/cinder/connection-indicator';\n</script>\n\n<ConnectionIndicator status=\"live\" />\n"
11
+ },
12
+ {
13
+ "id": "polling",
14
+ "title": "Polling vs live",
15
+ "description": "Polling reads quieter and different from live through icon, motion, and font-weight — not color alone.",
16
+ "code": "<script lang=\"ts\">\n import { ConnectionIndicator } from '@lostgradient/cinder/connection-indicator';\n</script>\n\n<div class=\"example-preview-row\">\n <ConnectionIndicator status=\"live\" />\n <ConnectionIndicator status=\"polling\" />\n</div>\n"
17
+ },
18
+ {
19
+ "id": "reconnecting",
20
+ "title": "Reconnecting with attempt count",
21
+ "description": "The reconnecting state showing a retry attempt via the attempt snippet.",
22
+ "code": "<script lang=\"ts\">\n import { ConnectionIndicator } from '@lostgradient/cinder/connection-indicator';\n</script>\n\n<ConnectionIndicator status=\"reconnecting\">\n {#snippet attempt()}\n attempt 3 of 5\n {/snippet}\n</ConnectionIndicator>\n"
23
+ },
24
+ {
25
+ "id": "states",
26
+ "title": "All connection states",
27
+ "description": "Each of the six states with its own icon and text label. Colors come from shared semantic tokens, so some states intentionally share a tone (e.g. connecting/reconnecting) — the icon and text carry the distinction, never color alone.",
28
+ "code": "<script lang=\"ts\">\n import { ConnectionIndicator } from '@lostgradient/cinder/connection-indicator';\n</script>\n\n<div class=\"example-preview-row\">\n <ConnectionIndicator status=\"connecting\" />\n <ConnectionIndicator status=\"live\" />\n <ConnectionIndicator status=\"reconnecting\" />\n <ConnectionIndicator status=\"polling\" />\n <ConnectionIndicator status=\"stale\" />\n <ConnectionIndicator status=\"closed\" />\n</div>\n"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "status": {
6
+ "enum": ["connecting", "live", "reconnecting", "polling", "stale", "closed"],
7
+ "description": "Current connection lifecycle state. Drives icon, text, and color via `data-cinder-status`."
8
+ },
9
+ "label": {
10
+ "type": "string",
11
+ "description": "Optional human label override. Replaces the default text for `status` (and the \"Connection: …\" accessible name)."
12
+ },
13
+ "class": {
14
+ "type": "string",
15
+ "description": "Extra classes appended to the root element."
16
+ }
17
+ },
18
+ "additionalProperties": false,
19
+ "required": ["status"],
20
+ "metadata": {
21
+ "unsupportedProps": [
22
+ {
23
+ "name": "attempt",
24
+ "reason": "function-or-snippet",
25
+ "description": "Attempt-count content rendered next to the label when `status` is `'reconnecting'`, e.g. \"attempt 3 of 5\". Ignored for other states."
26
+ }
27
+ ]
28
+ }
29
+ }
@@ -0,0 +1,36 @@
1
+ import type { ComponentSchema } from '../../schema-types';
2
+
3
+ const schema = {
4
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
5
+ type: 'object',
6
+ properties: {
7
+ status: {
8
+ enum: ['connecting', 'live', 'reconnecting', 'polling', 'stale', 'closed'],
9
+ description:
10
+ 'Current connection lifecycle state. Drives icon, text, and color via `data-cinder-status`.',
11
+ },
12
+ label: {
13
+ type: 'string',
14
+ description:
15
+ 'Optional human label override. Replaces the default text for `status` (and the "Connection: …" accessible name).',
16
+ },
17
+ class: {
18
+ type: 'string',
19
+ description: 'Extra classes appended to the root element.',
20
+ },
21
+ },
22
+ additionalProperties: false,
23
+ required: ['status'],
24
+ metadata: {
25
+ unsupportedProps: [
26
+ {
27
+ name: 'attempt',
28
+ reason: 'function-or-snippet',
29
+ description:
30
+ 'Attempt-count content rendered next to the label when `status` is `\'reconnecting\'`, e.g. "attempt 3 of 5". Ignored for other states.',
31
+ },
32
+ ],
33
+ },
34
+ } satisfies ComponentSchema;
35
+
36
+ export default schema as ComponentSchema;
@@ -0,0 +1,63 @@
1
+ <script lang="ts" module>
2
+ export {};
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import Loader from 'lucide-svelte/icons/loader';
7
+ import RefreshCcwDot from 'lucide-svelte/icons/refresh-ccw-dot';
8
+ import RefreshCw from 'lucide-svelte/icons/refresh-cw';
9
+ import TriangleAlert from 'lucide-svelte/icons/triangle-alert';
10
+ import Wifi from 'lucide-svelte/icons/wifi';
11
+ import WifiOff from 'lucide-svelte/icons/wifi-off';
12
+ import { classNames } from '../../utilities/class-names.ts';
13
+ const statusLabels = {
14
+ connecting: 'Connecting',
15
+ live: 'Live',
16
+ reconnecting: 'Reconnecting',
17
+ polling: 'Polling',
18
+ stale: 'Stale',
19
+ closed: 'Closed',
20
+ };
21
+ const statusIcons = {
22
+ connecting: Loader,
23
+ live: Wifi,
24
+ reconnecting: RefreshCw,
25
+ polling: RefreshCcwDot,
26
+ stale: TriangleAlert,
27
+ closed: WifiOff,
28
+ };
29
+ let { status, label, attempt, class: className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, ...rest } = $props();
30
+ // Normalize empty/whitespace-only ARIA name props to `undefined` so an empty
31
+ // attribute is never emitted (which would suppress the accessible-name
32
+ // fallback). A provided aria-labelledby takes precedence, so the automatic
33
+ // aria-label default steps aside for it.
34
+ const normalizedAriaLabel = $derived(ariaLabel?.trim() ? ariaLabel.trim() : undefined);
35
+ const normalizedAriaLabelledby = $derived(ariaLabelledby?.trim() ? ariaLabelledby.trim() : undefined);
36
+ const resolvedLabel = $derived(label?.trim() ? label.trim() : statusLabels[status]);
37
+ const resolvedAriaLabel = $derived(normalizedAriaLabelledby !== undefined
38
+ ? undefined
39
+ : (normalizedAriaLabel ?? `Connection: ${resolvedLabel}`));
40
+ const Icon = $derived(statusIcons[status]);
41
+ </script>
42
+
43
+ <div
44
+ {...rest}
45
+ class={classNames('cinder-connection-indicator', className)}
46
+ data-cinder-status={status}
47
+ role="status"
48
+ aria-live="polite"
49
+ aria-atomic="true"
50
+ aria-label={resolvedAriaLabel}
51
+ aria-labelledby={normalizedAriaLabelledby}
52
+ >
53
+ {#if status === 'live'}
54
+ <span class="cinder-connection-indicator__dot" aria-hidden="true"></span>
55
+ {/if}
56
+ <span class="cinder-connection-indicator__icon" aria-hidden="true">
57
+ <Icon size={13} strokeWidth={2.25} />
58
+ </span>
59
+ <span class="cinder-connection-indicator__label">{resolvedLabel}</span>
60
+ {#if status === 'reconnecting' && attempt}
61
+ <span class="cinder-connection-indicator__attempt">{@render attempt()}</span>
62
+ {/if}
63
+ </div>
@@ -0,0 +1,58 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+
4
+ /**
5
+ * The six connection lifecycle states ConnectionIndicator understands.
6
+ *
7
+ * Stamped directly onto the root as `data-cinder-status` and driving color
8
+ * exclusively through `connection-indicator.css` — there are no hard-coded
9
+ * color classes on the component. Each state also carries its own icon and
10
+ * text label so status is never communicated by color alone (WCAG 1.4.1).
11
+ *
12
+ * - `connecting` — initial handshake in progress, no data yet.
13
+ * - `live` — connected and actively receiving pushed updates.
14
+ * - `reconnecting` — a previously live connection dropped and is retrying.
15
+ * - `polling` — receiving updates via interval polling rather than push.
16
+ * - `stale` — connected but data has not refreshed within an expected window.
17
+ * - `closed` — the connection is intentionally or terminally closed.
18
+ */
19
+ export type ConnectionIndicatorStatus =
20
+ | 'connecting'
21
+ | 'live'
22
+ | 'reconnecting'
23
+ | 'polling'
24
+ | 'stale'
25
+ | 'closed';
26
+
27
+ /**
28
+ * Props for ConnectionIndicator.
29
+ *
30
+ * The component always renders `role="status"` with a computed accessible
31
+ * name of the form "Connection: {label}" (overridable via `aria-label`), so
32
+ * assistive technology gets the same signal as sighted users regardless of
33
+ * which visual treatment (icon, motion, font-weight) carries the difference
34
+ * between states.
35
+ */
36
+ export type ConnectionIndicatorProps = Omit<
37
+ HTMLAttributes<HTMLDivElement>,
38
+ 'class' | 'children'
39
+ > & {
40
+ /** Current connection lifecycle state. Drives icon, text, and color via `data-cinder-status`. */
41
+ status: ConnectionIndicatorStatus;
42
+ /** Optional human label override. Replaces the default text for `status` (and the "Connection: …" accessible name). */
43
+ label?: string;
44
+ /** Attempt-count content rendered next to the label when `status` is `'reconnecting'`, e.g. "attempt 3 of 5". Ignored for other states. */
45
+ attempt?: Snippet;
46
+ /** Extra classes appended to the root element. */
47
+ class?: string;
48
+ };
49
+
50
+ /** Schema-facing mirror of {@link ConnectionIndicatorProps}, omitting the non-serializable `attempt` snippet and native HTML attribute passthrough. */
51
+ export interface ConnectionIndicatorSchemaProps {
52
+ /** Current connection lifecycle state. Drives icon, text, and color via `data-cinder-status`. */
53
+ status: ConnectionIndicatorStatus;
54
+ /** Optional human label override. Replaces the default text for `status` (and the "Connection: …" accessible name). */
55
+ label?: string;
56
+ /** Extra classes appended to the root element. */
57
+ class?: string;
58
+ }
@@ -0,0 +1,3 @@
1
+ const variables: readonly string[] = [];
2
+
3
+ export default variables;
@@ -0,0 +1,10 @@
1
+ import './connection-indicator.css';
2
+ import ConnectionIndicator from './connection-indicator.svelte';
3
+
4
+ export default ConnectionIndicator;
5
+ export type {
6
+ ConnectionIndicatorProps,
7
+ ConnectionIndicatorSchemaProps,
8
+ ConnectionIndicatorStatus,
9
+ } from './connection-indicator.types.ts';
10
+ export { ConnectionIndicator };
@@ -19,6 +19,9 @@
19
19
  "as": {
20
20
  "enum": [
21
21
  "object",
22
+ "slot",
23
+ "style",
24
+ "title",
22
25
  "a",
23
26
  "abbr",
24
27
  "address",
@@ -94,11 +97,9 @@
94
97
  "search",
95
98
  "section",
96
99
  "select",
97
- "slot",
98
100
  "small",
99
101
  "span",
100
102
  "strong",
101
- "style",
102
103
  "sub",
103
104
  "summary",
104
105
  "sup",
@@ -111,7 +112,6 @@
111
112
  "th",
112
113
  "thead",
113
114
  "time",
114
- "title",
115
115
  "tr",
116
116
  "u",
117
117
  "ul",
@@ -21,6 +21,9 @@ const schema = {
21
21
  as: {
22
22
  enum: [
23
23
  'object',
24
+ 'slot',
25
+ 'style',
26
+ 'title',
24
27
  'a',
25
28
  'abbr',
26
29
  'address',
@@ -96,11 +99,9 @@ const schema = {
96
99
  'search',
97
100
  'section',
98
101
  'select',
99
- 'slot',
100
102
  'small',
101
103
  'span',
102
104
  'strong',
103
- 'style',
104
105
  'sub',
105
106
  'summary',
106
107
  'sup',
@@ -113,7 +114,6 @@ const schema = {
113
114
  'th',
114
115
  'thead',
115
116
  'time',
116
- 'title',
117
117
  'tr',
118
118
  'u',
119
119
  'ul',
@@ -10,6 +10,10 @@
10
10
  "type": "string",
11
11
  "description": "Current text search query. When provided, the search field is controlled."
12
12
  },
13
+ "showSearch": {
14
+ "type": "boolean",
15
+ "description": "Whether to render the leading search field. Defaults to `true`."
16
+ },
13
17
  "searchPlaceholder": {
14
18
  "type": "string",
15
19
  "description": "Placeholder text shown in the leading search field."
@@ -12,6 +12,10 @@ const schema = {
12
12
  type: 'string',
13
13
  description: 'Current text search query. When provided, the search field is controlled.',
14
14
  },
15
+ showSearch: {
16
+ type: 'boolean',
17
+ description: 'Whether to render the leading search field. Defaults to `true`.',
18
+ },
15
19
  searchPlaceholder: {
16
20
  type: 'string',
17
21
  description: 'Placeholder text shown in the leading search field.',
@@ -10,7 +10,7 @@ import Chip from '../chip/chip.svelte';
10
10
  import Button from '../button/button.svelte';
11
11
  import { classNames } from '../../utilities/class-names.ts';
12
12
  const generatedId = $props.id();
13
- let { 'aria-label': ariaLabel = 'Filters', searchQuery, searchPlaceholder = 'Search…', searchAriaLabel = 'Search', facets = [], appliedFilters = [], disabled = false, class: className, onsearchchange, onfacetchange, onfilterremove, onclearall, ...rest } = $props();
13
+ let { 'aria-label': ariaLabel = 'Filters', searchQuery, showSearch = true, searchPlaceholder = 'Search…', searchAriaLabel = 'Search', facets = [], appliedFilters = [], disabled = false, class: className, onsearchchange, onfacetchange, onfilterremove, onclearall, ...rest } = $props();
14
14
  const searchId = $derived(`${generatedId}-search`);
15
15
  let rootElement = $state();
16
16
  // Internal uncontrolled search value when searchQuery is not provided.
@@ -32,7 +32,7 @@ function resolveFilterDisplayValue(key, value) {
32
32
  return value;
33
33
  return facet.options.find((option) => option.value === value)?.label ?? value;
34
34
  }
35
- const hasAppliedFilters = $derived(appliedFilters.length > 0 || currentSearchQuery.length > 0);
35
+ const hasAppliedFilters = $derived(appliedFilters.length > 0 || (showSearch && currentSearchQuery.length > 0));
36
36
  const totalActiveCount = $derived(appliedFilters.length);
37
37
  // Live region summary message — always in DOM, content changes when filters change.
38
38
  const summaryMessage = $derived.by(() => {
@@ -81,15 +81,17 @@ function getFacetCurrentValue(key) {
81
81
  >
82
82
  <!-- Controls row: search field + facet selects -->
83
83
  <div class="cinder-faceted-filter-bar__controls">
84
- <SearchField
85
- id={searchId}
86
- class="cinder-faceted-filter-bar__search"
87
- value={currentSearchQuery}
88
- placeholder={searchPlaceholder}
89
- aria-label={searchAriaLabel}
90
- {disabled}
91
- oninput={handleSearchInput}
92
- />
84
+ {#if showSearch}
85
+ <SearchField
86
+ id={searchId}
87
+ class="cinder-faceted-filter-bar__search"
88
+ value={currentSearchQuery}
89
+ placeholder={searchPlaceholder}
90
+ aria-label={searchAriaLabel}
91
+ {disabled}
92
+ oninput={handleSearchInput}
93
+ />
94
+ {/if}
93
95
 
94
96
  {#each facets as facet (facet.key)}
95
97
  {#if facet.type === 'select'}
@@ -69,6 +69,8 @@ export type FacetedFilterBarProps = Omit<HTMLAttributes<HTMLDivElement>, 'class'
69
69
  'aria-label'?: string;
70
70
  /** Current text search query. When provided, the search field is controlled. */
71
71
  searchQuery?: string;
72
+ /** Whether to render the leading search field. Defaults to `true`. */
73
+ showSearch?: boolean;
72
74
  /** Placeholder text shown in the leading search field. */
73
75
  searchPlaceholder?: string;
74
76
  /** Accessible label for the search input. Defaults to 'Search'. */
@@ -5,10 +5,14 @@ export default InvocationRuleBuilder;
5
5
  export type {
6
6
  InvocationRule,
7
7
  InvocationRuleAction,
8
+ InvocationRuleBuilderMode,
8
9
  InvocationRuleBuilderProps,
9
10
  InvocationRuleBuilderSchemaProps,
10
11
  InvocationRuleChange,
11
12
  InvocationRuleCondition,
13
+ InvocationRuleConditionsOnlyOperator,
14
+ InvocationRuleFieldType,
12
15
  InvocationRuleOption,
16
+ InvocationRuleValueChoice,
13
17
  } from './invocation-rule-builder.types.ts';
14
18
  export { InvocationRuleBuilder };
@@ -160,6 +160,34 @@
160
160
  }
161
161
  }
162
162
 
163
+ /* ---- Typed condition value controls (conditions-only mode) ---- */
164
+
165
+ /* Enum values reuse the select chrome but keep the value input's wider flex-basis. */
166
+ .cinder-invocation-rule-builder__condition-value-select {
167
+ flex: 2 1 10rem;
168
+ min-inline-size: 6rem;
169
+ }
170
+
171
+ .cinder-invocation-rule-builder__condition-value-checkbox {
172
+ flex: 0 0 auto;
173
+ inline-size: 1.125rem;
174
+ block-size: 1.125rem;
175
+ margin: 0;
176
+ accent-color: var(--cinder-accent);
177
+ cursor: pointer;
178
+ }
179
+
180
+ .cinder-invocation-rule-builder__condition-value-checkbox:focus-visible {
181
+ outline: var(--cinder-ring-width) solid transparent;
182
+ box-shadow: var(--_cinder-focus-ring-shadow);
183
+ }
184
+
185
+ @media (forced-colors: active) {
186
+ .cinder-invocation-rule-builder__condition-value-checkbox:focus-visible {
187
+ outline: var(--cinder-ring-width) solid ButtonText;
188
+ }
189
+ }
190
+
163
191
  /* ---- Action rows ---- */
164
192
 
165
193
  .cinder-invocation-rule-builder__actions {
@@ -9,6 +9,12 @@
9
9
  "description": "Configure which code review agents run based on pull request conditions such as changed paths, labels, and author membership.",
10
10
  "code": "<script lang=\"ts\">\n import {\n InvocationRuleBuilder,\n type InvocationRule,\n type InvocationRuleChange,\n type InvocationRuleOption,\n } from '@lostgradient/cinder/invocation-rule-builder';\n\n const fieldOptions: InvocationRuleOption[] = [\n { value: 'path', label: 'Path' },\n { value: 'label', label: 'Label' },\n { value: 'author-role', label: 'Author role' },\n { value: 'event-type', label: 'Event type' },\n { value: 'check-status', label: 'Check status' },\n ];\n\n const operatorOptions: InvocationRuleOption[] = [\n { value: 'matches', label: 'matches' },\n { value: 'is', label: 'is' },\n { value: 'is-not', label: 'is not' },\n { value: 'contains', label: 'contains' },\n { value: 'failed', label: 'failed' },\n ];\n\n const actionOptions: InvocationRuleOption[] = [\n { value: 'security-reviewer', label: 'Security Reviewer' },\n { value: 'code-quality', label: 'Code Quality Agent' },\n { value: 'dependency-audit', label: 'Dependency Audit' },\n { value: 'performance-review', label: 'Performance Review' },\n ];\n\n let rules = $state<InvocationRule[]>([\n {\n id: 'rule-security',\n label: 'Security review for sensitive paths',\n conditions: [\n { id: 'c1', field: 'path', operator: 'matches', value: 'src/auth/**' },\n { id: 'c2', field: 'path', operator: 'matches', value: 'src/crypto/**' },\n ],\n actions: [{ id: 'a1', target: 'security-reviewer' }],\n },\n {\n id: 'rule-deps',\n label: 'Dependency changes',\n conditions: [{ id: 'c3', field: 'path', operator: 'matches', value: 'package.json' }],\n actions: [{ id: 'a2', target: 'dependency-audit' }],\n },\n ]);\n\n function handleChange(nextRules: InvocationRule[], _change: InvocationRuleChange): void {\n rules = nextRules;\n }\n</script>\n\n<InvocationRuleBuilder\n {rules}\n onchange={handleChange}\n {fieldOptions}\n {operatorOptions}\n {actionOptions}\n label=\"PR routing rules\"\n/>\n"
11
11
  },
12
+ {
13
+ "id": "conditions-only",
14
+ "title": "Conditions-only mode",
15
+ "description": "Build alert-filter conditions with typed value inputs and a fixed comparison-operator set — no action targets, for cases like saved searches or alert filters that have nothing to invoke.",
16
+ "code": "<script lang=\"ts\">\n import {\n InvocationRuleBuilder,\n type InvocationRule,\n type InvocationRuleChange,\n type InvocationRuleOption,\n } from '@lostgradient/cinder/invocation-rule-builder';\n\n const fieldOptions: InvocationRuleOption[] = [\n { value: 'retry-count', label: 'Retry count', type: 'number' },\n { value: 'is-flaky', label: 'Flaky', type: 'boolean' },\n {\n value: 'severity',\n label: 'Severity',\n type: 'enum',\n options: [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n ],\n },\n { value: 'owner', label: 'Owner' },\n ];\n\n let rules = $state<InvocationRule[]>([\n {\n id: 'rule-flaky-high-severity',\n label: 'Flaky high-severity retries',\n conditions: [\n { id: 'c1', field: 'is-flaky', operator: 'eq', value: 'true' },\n { id: 'c2', field: 'severity', operator: 'eq', value: 'high' },\n { id: 'c3', field: 'retry-count', operator: 'gte', value: '3' },\n ],\n actions: [],\n },\n ]);\n\n function handleChange(nextRules: InvocationRule[], _change: InvocationRuleChange): void {\n rules = nextRules;\n }\n</script>\n\n<InvocationRuleBuilder\n {rules}\n onchange={handleChange}\n {fieldOptions}\n mode=\"conditions\"\n label=\"Alert filter conditions\"\n/>\n"
17
+ },
12
18
  {
13
19
  "id": "readonly",
14
20
  "title": "Readonly rule summary",