@picked/svelte 0.0.1-dev.1770787109735 → 0.0.1-dev.1771901344537

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 (52) hide show
  1. package/dist/hooks/field.d.ts +2 -5
  2. package/dist/hooks/field.js +1 -1
  3. package/dist/hooks/index.d.ts +0 -1
  4. package/dist/hooks/index.js +1 -1
  5. package/dist/plugins/devtools/DevToolsExperience.svelte +107 -67
  6. package/dist/plugins/devtools/PickedIcon.svelte +19 -0
  7. package/dist/plugins/devtools/components/ExperienceInstanceListItem.svelte +2 -1
  8. package/dist/plugins/devtools/components/ExperienceInstancesTable.svelte +26 -20
  9. package/dist/plugins/devtools/components/Tabs.svelte +20 -7
  10. package/dist/plugins/devtools/experience.js +1 -1
  11. package/dist/plugins/devtools/screens/components/ComponentsListScreen.svelte +18 -14
  12. package/dist/plugins/devtools/screens/events/EventListItem.svelte +128 -0
  13. package/dist/plugins/devtools/screens/events/EventsListScreen.svelte +18 -0
  14. package/dist/plugins/devtools/screens/events/EventsTable.svelte +76 -0
  15. package/dist/plugins/devtools/screens/experience-instances/ExperienceInstancesListScreen.svelte +1 -3
  16. package/dist/plugins/devtools/screens/experiences/ExperienceDetailsScreen.svelte +34 -33
  17. package/dist/plugins/devtools/screens/experiences/ExperienceExperienceInstancesListScreen.svelte +1 -3
  18. package/dist/plugins/devtools/screens/experiences/ExperienceTreeScreen.svelte +20 -71
  19. package/dist/plugins/devtools/screens/features/FeaturesListScreen.svelte +175 -0
  20. package/dist/plugins/devtools/screens/frameworks/FrameworksListScreen.svelte +15 -13
  21. package/dist/plugins/devtools/screens/history/HistoryEntriesTable.svelte +22 -16
  22. package/dist/plugins/devtools/screens/predicates/PredicatesListScreen.svelte +15 -13
  23. package/dist/plugins/devtools/screens/project/ProjectScreen.svelte +47 -1
  24. package/dist/plugins/devtools/screens/responses/ResponseTableRow.svelte +25 -63
  25. package/dist/plugins/devtools/screens/responses/ResponsesTable.svelte +46 -65
  26. package/dist/plugins/devtools/ui/actions/Button.svelte +175 -0
  27. package/dist/plugins/devtools/ui/actions/CopyButton.svelte +88 -0
  28. package/dist/plugins/devtools/ui/data/Badge.svelte +62 -0
  29. package/dist/plugins/devtools/ui/data/CodeBlock.svelte +38 -0
  30. package/dist/plugins/devtools/ui/data/DataTable.svelte +144 -0
  31. package/dist/plugins/devtools/ui/data/EmptyState.svelte +26 -0
  32. package/dist/plugins/devtools/ui/data/ExpandableRow.svelte +66 -0
  33. package/dist/plugins/devtools/ui/data/VisualizationContainer.svelte +55 -0
  34. package/dist/plugins/devtools/ui/feedback/Banner.svelte +116 -0
  35. package/dist/plugins/devtools/ui/feedback/Spinner.svelte +79 -0
  36. package/dist/plugins/devtools/ui/forms/Checkbox.svelte +139 -0
  37. package/dist/plugins/devtools/ui/forms/RadioGroup.svelte +218 -0
  38. package/dist/plugins/devtools/ui/forms/Select.svelte +137 -0
  39. package/dist/plugins/devtools/ui/forms/Switch.svelte +158 -0
  40. package/dist/plugins/devtools/ui/forms/TextField.svelte +125 -0
  41. package/dist/plugins/devtools/ui/index.d.ts +22 -0
  42. package/dist/plugins/devtools/ui/index.js +1 -0
  43. package/dist/plugins/devtools/ui/layout/Card.svelte +55 -0
  44. package/dist/plugins/devtools/ui/layout/Divider.svelte +34 -0
  45. package/dist/plugins/devtools/ui/layout/Spacer.svelte +11 -0
  46. package/dist/plugins/devtools/ui/layout/Stack.svelte +129 -0
  47. package/dist/plugins/devtools/ui/overlays/Tooltip.svelte +90 -0
  48. package/dist/plugins/devtools/ui/tokens.css +144 -0
  49. package/dist/plugins/devtools/ui/tokens.css.js +1 -0
  50. package/dist/plugins/devtools/ui/typography/Heading.svelte +55 -0
  51. package/dist/plugins/devtools/ui/typography/Text.svelte +93 -0
  52. package/package.json +17 -2
@@ -1,10 +1,7 @@
1
- import { Field, FieldValue, FieldOptionArray, JsonValue } from '@picked/client';
1
+ import { Field, FieldValue } from '@picked/client';
2
2
  import { Store } from 'effector';
3
3
  export interface GetFieldResponse {
4
- field: Store<Field | null>;
5
4
  value: Store<FieldValue>;
6
- options: Store<FieldOptionArray<JsonValue> | null>;
7
- isLoading: Store<boolean>;
8
- error: Store<string | null>;
5
+ field: Store<Field | null>;
9
6
  }
10
7
  export declare function getField(id: string): GetFieldResponse;
@@ -1 +1 @@
1
- import{getPicked as i}from"./client.js";function r(t){const o=i();o.fields.resolve(t);const s=o.fields.getByFieldId(t);return{field:o.fields.getById(t),value:o.responses.getByFieldId(t),options:s.map(e=>e.options),isLoading:s.map(e=>e.status==="loading"||e.status==="idle"),error:s.map(e=>e.error??null)}}export{r as getField};
1
+ import{getPicked as s}from"./client.js";function r(e){const t=s(),n=t.fields.getById(e),o=t.responses.getByFieldId(e);return{field:n,value:o}}export{r as getField};
@@ -1,5 +1,4 @@
1
1
  export { getPicked, getExperience } from './client';
2
- export { getField } from './field';
3
2
  export { getPredicate, getPredicateResult } from './predicate';
4
3
  export { getFeature, getFeatureResult } from './feature';
5
4
  export { getAction, getActionResult } from './action';
@@ -1 +1 @@
1
- import{getExperience as r,getPicked as o}from"./client.js";import{getField as p}from"./field.js";import{getPredicate as x,getPredicateResult as a}from"./predicate.js";import{getFeature as n,getFeatureResult as s}from"./feature.js";import{getAction as i,getActionResult as u}from"./action.js";import{getStep as d,setStepContext as l}from"./step.js";import{getContextScope as C,setContextScope as R,useUnit as y}from"./stores.js";import{createLocalStorageStore as k,createSessionStorageStore as q}from"./storage.js";import{getTrackRecommendationPresentEvent as E}from"./events.js";import{createQuery as v,queryCache as L,queryPresets as Q}from"./create-query/index.js";export{k as createLocalStorageStore,v as createQuery,q as createSessionStorageStore,i as getAction,u as getActionResult,C as getContextScope,r as getExperience,n as getFeature,s as getFeatureResult,p as getField,o as getPicked,x as getPredicate,a as getPredicateResult,d as getStep,E as getTrackRecommendationPresentEvent,L as queryCache,Q as queryPresets,R as setContextScope,l as setStepContext,y as useUnit};
1
+ import{getExperience as r,getPicked as o}from"./client.js";import{getPredicate as p,getPredicateResult as a}from"./predicate.js";import{getFeature as x,getFeatureResult as n}from"./feature.js";import{getAction as s,getActionResult as f}from"./action.js";import{getStep as u,setStepContext as S}from"./step.js";import{getContextScope as d,setContextScope as l,useUnit as C}from"./stores.js";import{createLocalStorageStore as y,createSessionStorageStore as k}from"./storage.js";import{getTrackRecommendationPresentEvent as A}from"./events.js";import{createQuery as F,queryCache as h,queryPresets as v}from"./create-query/index.js";export{y as createLocalStorageStore,F as createQuery,k as createSessionStorageStore,s as getAction,f as getActionResult,d as getContextScope,r as getExperience,x as getFeature,n as getFeatureResult,o as getPicked,p as getPredicate,a as getPredicateResult,u as getStep,A as getTrackRecommendationPresentEvent,h as queryCache,v as queryPresets,l as setContextScope,S as setStepContext,C as useUnit};
@@ -1,6 +1,13 @@
1
+ <!--
2
+ @paired-component apps/dashboard/src/shared/ui/layout/page.tsx
3
+ @design-parity The devtools modal layout mirrors the Dashboard Page component.
4
+ The toolbar, main area, padding, and border radius must stay visually identical
5
+ to the Dashboard's AppShell content area. When modifying this layout, replicate
6
+ the change in the paired React component to maintain visual and behavioral parity.
7
+ -->
1
8
  <script lang="ts">
2
- import { getExperience } from '../../hooks'
3
- import PickedLogo from './PickedLogo.svelte'
9
+ import { getExperience, getPicked } from '../../hooks'
10
+ import { Button, Heading, Stack } from './ui'
4
11
  import Tabs from './components/Tabs.svelte'
5
12
  import ExperiencesListScreen from './screens/experiences/ExperiencesListScreen.svelte'
6
13
  import ExperienceInstancesListScreen from './screens/experience-instances/ExperienceInstancesListScreen.svelte'
@@ -10,8 +17,14 @@
10
17
  import ProjectScreen from './screens/project/ProjectScreen.svelte'
11
18
  import HistoryEntriesListScreen from './screens/history/HistoryEntriesListScreen.svelte'
12
19
  import ResponsesListScreen from './screens/responses/ResponsesListScreen.svelte'
20
+ import FeaturesListScreen from './screens/features/FeaturesListScreen.svelte'
21
+ import EventsListScreen from './screens/events/EventsListScreen.svelte'
22
+ import PickedIcon from './PickedIcon.svelte'
13
23
 
14
24
  const experience = getExperience()
25
+ const client = getPicked()
26
+
27
+ const dashboardProjectUrl = `${client.dashboardUrl}/p/${client.projectId}`
15
28
 
16
29
  const tabs = [
17
30
  {
@@ -26,6 +39,12 @@
26
39
  component: HistoryEntriesListScreen,
27
40
  props: {},
28
41
  },
42
+ {
43
+ id: 'events',
44
+ label: 'Events',
45
+ component: EventsListScreen,
46
+ props: {},
47
+ },
29
48
  {
30
49
  id: 'responses',
31
50
  label: 'Responses',
@@ -50,6 +69,12 @@
50
69
  component: PredicatesListScreen,
51
70
  props: {},
52
71
  },
72
+ {
73
+ id: 'features',
74
+ label: 'Features',
75
+ component: FeaturesListScreen,
76
+ props: {},
77
+ },
53
78
  {
54
79
  id: 'components',
55
80
  label: 'Components',
@@ -77,9 +102,19 @@
77
102
  >
78
103
  <div class="backdrop"></div>
79
104
  <div class="container">
80
- <header class="header" id="devtools-header">
81
- <PickedLogo />
82
- <button on:click={() => experience.close()}>Close</button>
105
+ <header class="toolbar" id="devtools-header">
106
+ <div class="toolbar-left">
107
+ <Stack direction="horizontal" gap="small" >
108
+ <PickedIcon height={25} width={25}/>
109
+ <Heading size="small">Developer Tools</Heading>
110
+ </Stack>
111
+ </div>
112
+ <div class="toolbar-center"></div>
113
+ <div class="toolbar-right">
114
+ <Button variant="ghost" size="small" href={client.documentationSiteUrl} target="_blank">Docs</Button>
115
+ <Button variant="ghost" size="small" href={dashboardProjectUrl} target="_blank">Dashboard</Button>
116
+ <Button variant="ghost" size="small" onclick={() => experience.close()}>Close</Button>
117
+ </div>
83
118
  </header>
84
119
  <section class="main">
85
120
  <Tabs {tabs} initialTab={1} />
@@ -89,82 +124,86 @@
89
124
  {:else}
90
125
  <button
91
126
  class="floating-button"
92
- on:click={() => experience.open()}
127
+ onclick={() => experience.open()}
93
128
  aria-label="Open Picked Devtools"
94
129
  title="Open Picked Devtools (or press .)"
95
130
  >
96
- <PickedLogo />
131
+ <PickedIcon height={25} width={25}/>
97
132
  </button>
98
133
  {/if}
99
134
 
100
135
  <style>
101
136
  *,
102
137
  .devtools * {
103
- box-sizing: inherit;
138
+ box-sizing: border-box;
104
139
  }
105
140
 
106
141
  .devtools {
107
142
  position: fixed;
108
- top: 0;
109
- left: 0;
110
- width: 100%;
111
- height: 100%;
143
+ inset: 0;
112
144
  z-index: 999999999;
113
- padding: 2em;
145
+ padding: 48px;
114
146
  display: grid;
115
147
  place-items: center;
116
148
  overflow: hidden;
117
- font-size: 13px;
118
- color: black;
119
- line-height: 1;
120
- }
121
-
122
- .devtools button {
123
- font-size: 13px;
124
- color: black;
125
- line-height: 1;
126
149
  }
127
150
 
128
151
  .backdrop {
129
152
  position: fixed;
130
- top: 0;
131
- left: 0;
132
- width: 100%;
133
- height: 100%;
153
+ inset: 0;
134
154
  background-color: rgba(0, 0, 0, 0.5);
135
155
  z-index: 1;
136
156
  }
137
157
 
138
158
  .container {
139
- background-color: white;
159
+ background-color: var(--color-white);
160
+ border-radius: var(--radius-xl);
161
+ box-shadow: var(--shadow-lg);
140
162
  display: flex;
141
163
  flex-direction: column;
142
- padding: 0.5rem;
143
- border-radius: 4px;
144
- box-shadow: 4px 4px 4px #00000029;
145
- border: 1px solid lightgray;
164
+ overflow: hidden;
146
165
  z-index: 2;
147
- overflow: auto;
148
166
  width: 100%;
149
167
  height: 100%;
150
168
  }
151
169
 
152
- .header {
153
- height: 50px;
154
- border-bottom: 1px solid lightgray;
170
+ .toolbar {
171
+ height: 40px;
172
+ background-color: var(--color-white);
173
+ border-bottom: 1px solid var(--color-gray-200);
174
+ padding: 0 var(--space-4);
155
175
  display: flex;
156
176
  align-items: center;
157
- padding: 0.5em;
158
177
  justify-content: space-between;
178
+ flex-shrink: 0;
179
+ }
180
+
181
+ .toolbar-left {
182
+ display: flex;
183
+ align-items: center;
184
+ }
185
+
186
+ .toolbar-center {
187
+ display: flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+ }
191
+
192
+ .toolbar-right {
193
+ display: flex;
194
+ align-items: center;
195
+ gap: var(--space-1);
159
196
  }
160
197
 
161
198
  .main {
162
- flex: 1 1 auto;
163
- display: grid;
199
+ flex: 1;
200
+ background-color: var(--color-gray-50);
201
+ overflow: auto;
202
+ display: flex;
164
203
  flex-direction: column;
165
- height: 100%;
166
204
  }
167
205
 
206
+ /* Global table styles for screens that still use raw tables */
168
207
  .devtools :global(table) {
169
208
  width: 100%;
170
209
  border-collapse: collapse;
@@ -172,47 +211,48 @@
172
211
 
173
212
  .devtools :global(th),
174
213
  .devtools :global(td) {
175
- padding: 0.5rem;
214
+ padding: var(--space-2);
176
215
  text-align: left;
177
- border-bottom: 1px solid lightgray;
216
+ border-bottom: 1px solid var(--color-gray-200);
217
+ font-size: var(--text-sm);
218
+ color: var(--color-gray-900);
178
219
  }
179
220
 
180
221
  .devtools :global(th) {
181
- padding: 0.5rem;
182
- font-weight: normal;
183
- background-color: #f0f0f0;
222
+ font-weight: var(--font-medium);
223
+ background-color: var(--color-gray-50);
224
+ }
225
+
226
+ .devtools :global(th:first-child),
227
+ .devtools :global(td:first-child) {
228
+ padding-left: var(--space-4);
229
+ }
230
+
231
+ .devtools :global(th:last-child),
232
+ .devtools :global(td:last-child) {
233
+ padding-right: var(--space-4);
184
234
  }
185
235
 
186
236
  .floating-button {
187
237
  position: fixed;
188
- bottom: 1.5rem;
238
+ bottom: 1rem;
189
239
  right: 1.5rem;
190
- width: 4.5rem;
191
- height: 4.5rem;
192
- border-radius: 50%;
193
- background-color: white;
194
- border: 1px solid lightgray;
195
- box-shadow: 0 4px 12px rgba(21, 73, 255, 0.2);
196
- display: flex;
197
- align-items: center;
198
- justify-content: center;
240
+ border-radius: 6px;
241
+ background-color: var(--color-white);
242
+ display: grid;
243
+ place-items: center;
199
244
  cursor: pointer;
200
245
  z-index: 999999;
201
- transition: all 0.2s ease;
202
- padding: 0;
203
- }
246
+ border: 0 transparent;
247
+ padding: 6px;
248
+ box-shadow: 2px 2px 4px #00000029;
204
249
 
205
- .floating-button:hover {
206
- box-shadow: 0 6px 16px rgba(21, 73, 255, 0.3);
207
- transform: scale(1.05);
250
+ &:hover {
251
+ background-color: #f5f5f5;
252
+ }
208
253
  }
209
254
 
210
- .floating-button:active {
211
- transform: scale(0.95);
212
- }
213
255
 
214
- .floating-button :global(svg) {
215
- width: 2.25rem;
216
- height: 2.25rem;
217
- }
256
+
257
+
218
258
  </style>
@@ -0,0 +1,19 @@
1
+ <!-- PickedIcon.svelte -->
2
+ <script lang="ts">
3
+ export let width = 48
4
+ export let height = 48
5
+ </script>
6
+
7
+ <svg {width} {height} viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
8
+ <g opacity="0.5">
9
+ <ellipse opacity="0.8" cx="32.5807" cy="7.38424" rx="6.29832" ry="6.29832" fill="#01AD7A"/>
10
+ <circle opacity="0.6" cx="31.4947" cy="8.47015" r="6.29832" fill="#01AD7A"/>
11
+ <ellipse opacity="0.4" cx="30.4088" cy="9.55607" rx="6.29832" ry="6.29832" fill="#01AD7A"/>
12
+ <ellipse opacity="0.2" cx="29.3229" cy="10.642" rx="6.29832" ry="6.29832" fill="#01AD7A"/>
13
+ <circle opacity="0.1" cx="28.237" cy="11.7279" r="6.29832" fill="#01AD7A"/>
14
+ </g>
15
+ <ellipse cx="33.6664" cy="6.29832" rx="6.29832" ry="6.29832" fill="#00CD90"/>
16
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5997 16.1802C14.5788 16.1802 16.1832 14.5758 16.1832 12.5967C16.1832 10.6175 14.5788 9.01315 12.5997 9.01315C10.6206 9.01315 9.01617 10.6175 9.01617 12.5967C9.01617 14.5758 10.6206 16.1802 12.5997 16.1802ZM12.5997 18.895C16.0782 18.895 18.898 16.0751 18.898 12.5967C18.898 9.11821 16.0782 6.29836 12.5997 6.29836C9.12123 6.29836 6.30138 9.11821 6.30138 12.5967C6.30138 16.0751 9.12123 18.895 12.5997 18.895Z" fill="#1549FF"/>
17
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5997 30.9486C14.5788 30.9486 16.1832 29.3442 16.1832 27.3651C16.1832 25.386 14.5788 23.7816 12.5997 23.7816C10.6206 23.7816 9.01617 25.386 9.01617 27.3651C9.01617 29.3442 10.6206 30.9486 12.5997 30.9486ZM12.5997 33.6634C16.0782 33.6634 18.898 30.8436 18.898 27.3651C18.898 23.8866 16.0782 21.0668 12.5997 21.0668C9.12123 21.0668 6.30138 23.8866 6.30138 27.3651C6.30138 30.8436 9.12123 33.6634 12.5997 33.6634Z" fill="#1549FF"/>
18
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M27.3683 30.9486C29.3474 30.9486 30.9518 29.3442 30.9518 27.3651C30.9518 25.386 29.3474 23.7816 27.3683 23.7816C25.3891 23.7816 23.7847 25.386 23.7847 27.3651C23.7847 29.3442 25.3891 30.9486 27.3683 30.9486ZM27.3683 33.6634C30.8467 33.6634 33.6666 30.8436 33.6666 27.3651C33.6666 23.8866 30.8467 21.0668 27.3683 21.0668C23.8898 21.0668 21.0699 23.8866 21.0699 27.3651C21.0699 30.8436 23.8898 33.6634 27.3683 33.6634Z" fill="#1549FF"/>
19
+ </svg>
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { ExperienceInstance } from '@picked/client'
3
+ import { Button } from '../ui'
3
4
 
4
5
  export let experienceInstance: ExperienceInstance
5
6
 
@@ -15,7 +16,7 @@
15
16
 
16
17
  <tr>
17
18
  <td>{experienceInstance.experienceId}</td>
18
- <td><button onclick={() => experienceInstance.toggleOpen()}>{$isOpen}</button></td>
19
+ <td><Button variant="ghost" size="small" onclick={() => experienceInstance.toggleOpen()}>{$isOpen}</Button></td>
19
20
  <td>{$currentNode?.id || ''}</td>
20
21
  <td>{$currentNode?.type || ''}</td>
21
22
  <td>{$currentStep?.id || ''}</td>
@@ -1,27 +1,33 @@
1
1
  <script lang="ts">
2
2
  import type { ExperienceInstance } from '@picked/client'
3
3
  import ExperienceInstanceListItem from './ExperienceInstanceListItem.svelte'
4
+ import { Card, DataTable, EmptyState, Stack } from '../ui'
4
5
 
5
6
  export let experienceInstances: ExperienceInstance[]
7
+
8
+ const columns = [
9
+ { key: 'experience', header: 'Experience' },
10
+ { key: 'isOpen', header: 'Is Open' },
11
+ { key: 'currentNodeId', header: 'Current node ID' },
12
+ { key: 'currentNodeType', header: 'Current node Type' },
13
+ { key: 'currentStepId', header: 'Current step ID' },
14
+ { key: 'currentStepTitle', header: 'Current step Title' },
15
+ { key: 'nextSteps', header: 'Next reachable steps amount' },
16
+ { key: 'stepsToOrigin', header: 'Steps to origin' },
17
+ { key: 'stepsToEnd', header: 'Steps to end' },
18
+ ]
6
19
  </script>
7
20
 
8
- <table>
9
- <thead>
10
- <tr>
11
- <th>Experience</th>
12
- <th>Is Open</th>
13
- <th>Current node ID</th>
14
- <th>Current node Type</th>
15
- <th>Current step ID</th>
16
- <th>Current step Title</th>
17
- <th>Next reachable steps amount</th>
18
- <th>Steps to origin</th>
19
- <th>Steps to end</th>
20
- </tr>
21
- </thead>
22
- <tbody>
23
- {#each experienceInstances as experienceInstance (experienceInstance.experienceId)}
24
- <ExperienceInstanceListItem {experienceInstance} />
25
- {/each}
26
- </tbody>
27
- </table>
21
+ <Stack padding="medium">
22
+ <Card sectioned>
23
+ <DataTable columns={columns} rows={experienceInstances}>
24
+ {#snippet row(item)}
25
+ {@const experienceInstance = item}
26
+ <ExperienceInstanceListItem {experienceInstance} />
27
+ {/snippet}
28
+ {#snippet empty()}
29
+ <EmptyState message="No experience instances" />
30
+ {/snippet}
31
+ </DataTable>
32
+ </Card>
33
+ </Stack>
@@ -82,37 +82,50 @@
82
82
  width: 100%;
83
83
  display: flex;
84
84
  flex-direction: column;
85
+ flex: 1;
85
86
  }
86
87
 
87
88
  .tab-list {
88
89
  display: flex;
89
- border-bottom: 1px solid #ccc;
90
+ border-bottom: 1px solid var(--color-gray-200);
91
+ flex-shrink: 0;
92
+ overflow-x: auto;
90
93
  }
91
94
 
92
95
  .tab-button {
93
- padding: 0.5rem 1rem;
96
+ padding: var(--space-2) var(--space-4);
94
97
  border: none;
95
98
  background: none;
96
99
  cursor: pointer;
97
100
  border-bottom: 2px solid transparent;
101
+ font-size: var(--text-sm);
102
+ color: var(--color-gray-600);
103
+ font-family: inherit;
104
+ white-space: nowrap;
105
+ transition: color 0.15s ease, border-color 0.15s ease;
98
106
  }
99
107
 
100
108
  .tab-button:hover {
101
- background-color: #f0f0f0;
109
+ background-color: var(--color-gray-100);
110
+ color: var(--color-gray-900);
102
111
  }
103
112
 
104
113
  .tab-button.active {
105
- border-bottom: 2px solid #000;
114
+ border-bottom-color: var(--color-gray-900);
115
+ color: var(--color-gray-900);
116
+ font-weight: var(--font-medium);
106
117
  }
107
118
 
108
- .tab-button:focus {
109
- outline: 2px solid #0066cc;
110
- outline-offset: -2px;
119
+ .tab-button:focus-visible {
120
+ outline: var(--ring-width) solid var(--ring-color);
121
+ outline-offset: calc(-1 * var(--ring-width));
111
122
  }
112
123
 
113
124
  .tab-panel {
114
125
  flex: 1 1 auto;
115
126
  display: grid;
127
+ align-content: start;
128
+ overflow: auto;
116
129
  }
117
130
 
118
131
  .tab-panel:not(.active) {
@@ -1 +1 @@
1
- import{createExperience as e}from"@picked/client/plugins/create-experience";import{adaptSvelteComponent as o}from"../../component.js";import t from"./DevToolsExperience.svelte";const p=e({id:"svelte-devtools",name:"Picked Devtools",decide:{},targets:[{selector:"body",placement:"append"}],component:o(t)});p.addStep({label:"Tools"});export{p as devtoolsExperience};
1
+ import{createExperience as e}from"@picked/client/plugins/create-experience";import{adaptSvelteComponent as o}from"../../component.js";import t from"./DevToolsExperience.svelte";import p from"./ui/tokens.css.js";const r=e({id:"svelte-devtools",name:"Picked Devtools",decide:{},targets:[{selector:"body",placement:"append"}],component:o(t,{css:[p]})});r.addStep({label:"Tools"});export{r as devtoolsExperience};
@@ -1,26 +1,30 @@
1
1
  <script lang="ts">
2
2
  import { getPicked } from '../../../../hooks'
3
+ import { Card, DataTable, EmptyState, Stack } from '../../ui'
3
4
 
4
5
  const client = getPicked()
5
6
 
6
7
  $: components = client.components.listStore
8
+
9
+ const columns = [
10
+ { key: 'name', header: 'Name' },
11
+ { key: 'framework', header: 'Framework' },
12
+ ]
7
13
  </script>
8
14
 
9
- <div>
10
- <table>
11
- <thead>
12
- <tr>
13
- <th>Name</th>
14
- <th>Framework</th>
15
- </tr>
16
- </thead>
17
- <tbody>
18
- {#each $components as component (component.name)}
15
+ <Stack padding="medium">
16
+ <Card sectioned>
17
+ <DataTable columns={columns} rows={$components}>
18
+ {#snippet row(item)}
19
+ {@const component = item}
19
20
  <tr>
20
21
  <td>{component.name}</td>
21
22
  <td>{component.component.frameworkName}</td>
22
23
  </tr>
23
- {/each}
24
- </tbody>
25
- </table>
26
- </div>
24
+ {/snippet}
25
+ {#snippet empty()}
26
+ <EmptyState message="No components" />
27
+ {/snippet}
28
+ </DataTable>
29
+ </Card>
30
+ </Stack>
@@ -0,0 +1,128 @@
1
+ <script lang="ts">
2
+ import type { EventBusPayload, EventHistoryEntry } from '@picked/client'
3
+ import { Badge, Card, CodeBlock, Stack, Text } from '../../ui'
4
+
5
+ export let event: EventHistoryEntry
6
+ export let isExpanded: boolean
7
+ export let onToggle: () => void
8
+
9
+ function formatTime(date: Date): string {
10
+ return date.toLocaleTimeString('en-US', {
11
+ hour12: false,
12
+ hour: '2-digit',
13
+ minute: '2-digit',
14
+ second: '2-digit',
15
+ fractionalSecondDigits: 3,
16
+ })
17
+ }
18
+
19
+ interface PayloadField {
20
+ label: string
21
+ value: unknown
22
+ }
23
+
24
+ function getPayloadFields(payload: EventBusPayload): PayloadField[] {
25
+ const fields: PayloadField[] = []
26
+
27
+ fields.push({ label: 'Type', value: payload.type })
28
+
29
+ if ('value' in payload && payload.value !== undefined) {
30
+ fields.push({ label: 'Value', value: payload.value })
31
+ }
32
+
33
+ if ('experience' in payload && payload.experience) {
34
+ const exp = payload.experience
35
+ if (exp && typeof exp === 'object') {
36
+ if ('id' in exp && exp.id) {
37
+ fields.push({ label: 'Experience ID', value: exp.id })
38
+ }
39
+ if ('experienceId' in exp && exp.experienceId) {
40
+ fields.push({ label: 'Experience Type', value: exp.experienceId })
41
+ }
42
+ }
43
+ }
44
+
45
+ if ('step' in payload && payload.step) {
46
+ const step = payload.step
47
+ if (step && typeof step === 'object') {
48
+ if ('id' in step && step.id) {
49
+ fields.push({ label: 'Step ID', value: step.id })
50
+ }
51
+ if ('label' in step && step.label) {
52
+ fields.push({ label: 'Step Label', value: step.label })
53
+ }
54
+ }
55
+ }
56
+
57
+ if ('form' in payload && payload.form) {
58
+ fields.push({ label: 'Form', value: JSON.stringify(payload.form) })
59
+ }
60
+
61
+ if ('feature' in payload && payload.feature) {
62
+ fields.push({ label: 'Feature', value: JSON.stringify(payload.feature) })
63
+ }
64
+
65
+ if ('exception' in payload && payload.exception) {
66
+ fields.push({ label: 'Exception', value: JSON.stringify(payload.exception) })
67
+ }
68
+
69
+ if ('version' in payload && payload.version) {
70
+ fields.push({ label: 'Version', value: payload.version })
71
+ }
72
+
73
+ if ('id' in payload && payload.id && payload.type === 'session') {
74
+ fields.push({ label: 'Session ID', value: payload.id })
75
+ }
76
+
77
+ return fields
78
+ }
79
+
80
+ function formatValue(value: unknown): string {
81
+ if (value === null) return 'null'
82
+ if (value === undefined) return 'undefined'
83
+ if (typeof value === 'string') return value
84
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value)
85
+ return JSON.stringify(value)
86
+ }
87
+ </script>
88
+
89
+ <tr class="event-row" onclick={onToggle}>
90
+ <td>
91
+ <span class="expand-icon">
92
+ {isExpanded ? '▼' : '▶'}
93
+ </span>
94
+ <CodeBlock code={formatTime(event.at)} inline />
95
+ </td>
96
+ <td>
97
+ <Badge status="info">{event.payload.type}</Badge>
98
+ </td>
99
+ <td>
100
+ <Text size="small">
101
+ {'experience' in event.payload && event.payload.experience ? event.payload.experience.experienceId : '-'}
102
+ </Text>
103
+ </td>
104
+ <td>
105
+ <Text size="caption" color="subdued">
106
+ {isExpanded ? 'Click to collapse' : 'Click to expand payload'}
107
+ </Text>
108
+ </td>
109
+ </tr>
110
+ {#if isExpanded}
111
+ <tr>
112
+ <td colspan="4" class="details-cell">
113
+ <Stack direction="vertical" gap="small">
114
+ <Text size="small" weight="semibold">Event Payload</Text>
115
+ <Card>
116
+ <Stack direction="vertical" gap="small">
117
+ {#each getPayloadFields(event.payload) as field}
118
+ <Text size="caption" inline>
119
+ <Text size="caption" weight="semibold" color="subdued" inline>{field.label}:</Text>
120
+ <CodeBlock code={formatValue(field.value)} inline />
121
+ </Text>
122
+ {/each}
123
+ </Stack>
124
+ </Card>
125
+ </Stack>
126
+ </td>
127
+ </tr>
128
+ {/if}
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import { getPicked } from '../../../../hooks'
3
+ import EventsTable from './EventsTable.svelte'
4
+ import { Divider, Spacer, Stack, Text } from '../../ui'
5
+
6
+ const { events } = getPicked()
7
+ </script>
8
+
9
+ <Stack direction="vertical" gap="none" fill>
10
+ <EventsTable />
11
+ <Spacer />
12
+ <Divider />
13
+ <Stack padding="small">
14
+ <Text size="caption" color="subdued">
15
+ {$events.length} events
16
+ </Text>
17
+ </Stack>
18
+ </Stack>