@astryxdesign/cli 0.6.3-canary.ea2f048 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
- package/package.json +9 -9
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
|
@@ -4,27 +4,11 @@
|
|
|
4
4
|
export const doc = {
|
|
5
5
|
type: 'block',
|
|
6
6
|
exampleFor: 'Toolbar',
|
|
7
|
-
alsoExampleFor: ['OverflowList'],
|
|
8
7
|
name: 'Toolbar — Table Filter',
|
|
9
8
|
displayName: 'Toolbar — Table Filter',
|
|
10
9
|
description:
|
|
11
|
-
'
|
|
10
|
+
'A compact toolbar with a search input, Status and Priority filter selectors, and an overflow menu. Use above a data table to let users search, filter, and access view options.',
|
|
12
11
|
isReady: true,
|
|
13
|
-
aspectRatio: 16 /
|
|
14
|
-
componentsUsed: [
|
|
15
|
-
'Toolbar',
|
|
16
|
-
'Selector',
|
|
17
|
-
'TextInput',
|
|
18
|
-
'OverflowList',
|
|
19
|
-
'Popover',
|
|
20
|
-
'Button',
|
|
21
|
-
'Icon',
|
|
22
|
-
'Link',
|
|
23
|
-
'Text',
|
|
24
|
-
'CheckboxList',
|
|
25
|
-
'Layout',
|
|
26
|
-
'Section',
|
|
27
|
-
'Table',
|
|
28
|
-
'EmptyState',
|
|
29
|
-
],
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: ['Toolbar', 'Selector', 'TextInput', 'MoreMenu', 'Layout', 'Table'],
|
|
30
14
|
};
|
|
@@ -2,402 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import * as stylex from '@stylexjs/stylex';
|
|
7
|
-
import {
|
|
8
|
-
borderVars,
|
|
9
|
-
colorVars,
|
|
10
|
-
radiusVars,
|
|
11
|
-
} from '@astryxdesign/core/theme/tokens.stylex';
|
|
5
|
+
import {useState} from 'react';
|
|
12
6
|
import {Toolbar} from '@astryxdesign/core/Toolbar';
|
|
13
7
|
import {Selector} from '@astryxdesign/core/Selector';
|
|
14
8
|
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {Link} from '@astryxdesign/core/Link';
|
|
20
|
-
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
21
|
-
import {CheckboxList, CheckboxListItem} from '@astryxdesign/core/CheckboxList';
|
|
22
|
-
import {Stack, StackItem, HStack, VStack} from '@astryxdesign/core/Layout';
|
|
23
|
-
import {Section} from '@astryxdesign/core/Section';
|
|
24
|
-
import {Table, pixel, proportional} from '@astryxdesign/core/Table';
|
|
25
|
-
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
26
|
-
import {EmptyState} from '@astryxdesign/core/EmptyState';
|
|
27
|
-
import {Columns3Cog, Search} from 'lucide-react';
|
|
28
|
-
|
|
29
|
-
interface Job extends Record<string, unknown> {
|
|
30
|
-
id: string;
|
|
31
|
-
job: string;
|
|
32
|
-
customer: string;
|
|
33
|
-
status: string;
|
|
34
|
-
priority: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const JOBS: Job[] = [
|
|
38
|
-
{
|
|
39
|
-
id: 'SJ-2136',
|
|
40
|
-
job: 'VAV zones not cooling',
|
|
41
|
-
customer: 'Northgate Dental',
|
|
42
|
-
status: 'In progress',
|
|
43
|
-
priority: 'High',
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
id: 'SJ-2135',
|
|
47
|
-
job: 'Exhaust fan noise',
|
|
48
|
-
customer: 'Riverside Club',
|
|
49
|
-
status: 'On hold',
|
|
50
|
-
priority: 'Normal',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
id: 'SJ-2134',
|
|
54
|
-
job: 'Humidifier board fault',
|
|
55
|
-
customer: 'Summit Medical',
|
|
56
|
-
status: 'Overdue',
|
|
57
|
-
priority: 'High',
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
id: 'SJ-2133',
|
|
61
|
-
job: 'Economizer stuck shut',
|
|
62
|
-
customer: 'Northgate Dental',
|
|
63
|
-
status: 'Scheduled',
|
|
64
|
-
priority: 'Normal',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: 'SJ-2101',
|
|
68
|
-
job: 'Contactor replacement',
|
|
69
|
-
customer: 'Harborview Hotel',
|
|
70
|
-
status: 'Completed',
|
|
71
|
-
priority: 'Low',
|
|
72
|
-
},
|
|
73
|
-
];
|
|
74
|
-
|
|
75
|
-
// One entry per filterable field. The closed trigger reads as the bare field
|
|
76
|
-
// name unset, and renderValue expands a set one to the whole clause, so each
|
|
77
|
-
// Selector doubles as its own filter chip.
|
|
78
|
-
const FIELDS = [
|
|
79
|
-
{
|
|
80
|
-
key: 'status',
|
|
81
|
-
label: 'Status',
|
|
82
|
-
options: ['Scheduled', 'In progress', 'On hold', 'Overdue', 'Completed'],
|
|
83
|
-
},
|
|
84
|
-
{key: 'priority', label: 'Priority', options: ['High', 'Normal', 'Low']},
|
|
85
|
-
{
|
|
86
|
-
key: 'customer',
|
|
87
|
-
label: 'Customer',
|
|
88
|
-
options: [
|
|
89
|
-
'Northgate Dental',
|
|
90
|
-
'Riverside Club',
|
|
91
|
-
'Summit Medical',
|
|
92
|
-
'Harborview Hotel',
|
|
93
|
-
],
|
|
94
|
-
},
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
const COLUMNS: TableColumn<Job>[] = [
|
|
98
|
-
{key: 'job', header: 'Job', width: proportional(2)},
|
|
99
|
-
{key: 'customer', header: 'Customer', width: proportional(2)},
|
|
100
|
-
{key: 'status', header: 'Status', width: pixel(110)},
|
|
101
|
-
{key: 'priority', header: 'Priority', width: pixel(90)},
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Width held back inside the clause slot for the readout that sits in it.
|
|
106
|
-
*
|
|
107
|
-
* The readout lives in the slot the overflow list measures, so without this
|
|
108
|
-
* the list would count its width as room for another clause and push it off
|
|
109
|
-
* the end. The slot pays for it as padding — the one part of the box the
|
|
110
|
-
* measurement already subtracts — and the readout takes it back with a
|
|
111
|
-
* matching negative margin, so it draws over the reserve and still lands
|
|
112
|
-
* against the last clause rather than at the row's far edge.
|
|
113
|
-
*/
|
|
114
|
-
const READOUT_RESERVE = 116;
|
|
115
|
-
|
|
116
|
-
const styles = stylex.create({
|
|
117
|
-
toolbarRow: {
|
|
118
|
-
// Grow so the row spans the toolbar: the clause slot inside it can only
|
|
119
|
-
// measure the width it is actually given.
|
|
120
|
-
flexGrow: 1,
|
|
121
|
-
minWidth: 0,
|
|
122
|
-
},
|
|
123
|
-
// Containment, not just a min-width reset: the reset lets flex squeeze this
|
|
124
|
-
// slot, but the toolbar's own slot still floors at the width this one
|
|
125
|
-
// reports it needs — the clauses at full length. Containment makes that
|
|
126
|
-
// report independent of the clauses, so the row settles inside the toolbar
|
|
127
|
-
// and the list finally reads a width that narrows. The popover it opens is
|
|
128
|
-
// portalled, so nothing the reader needs is inside the clip.
|
|
129
|
-
clauseSlot: {
|
|
130
|
-
display: 'flex',
|
|
131
|
-
alignItems: 'center',
|
|
132
|
-
minWidth: 0,
|
|
133
|
-
overflow: 'hidden',
|
|
134
|
-
containerType: 'inline-size',
|
|
135
|
-
// The held-back width, as padding (see READOUT_RESERVE).
|
|
136
|
-
paddingInlineEnd: READOUT_RESERVE,
|
|
137
|
-
},
|
|
138
|
-
// Fixed: the field is the row's anchor, so it keeps one width in every
|
|
139
|
-
// state. It still gives before the readout does, but only once the clauses
|
|
140
|
-
// have folded away and there is nothing else left to take.
|
|
141
|
-
searchSlot: {
|
|
142
|
-
flexShrink: 1,
|
|
143
|
-
minWidth: 120,
|
|
144
|
-
width: 120,
|
|
145
|
-
},
|
|
146
|
-
// The fill a control switches to once it carries a value, so a set clause is
|
|
147
|
-
// legible as engaged at a glance rather than only by reading it. This is the
|
|
148
|
-
// token ToggleButton paints for its own pressed state, so a set selector and
|
|
149
|
-
// a pressed control land on the same value over the same backdrop instead of
|
|
150
|
-
// two neighbouring shades of engaged.
|
|
151
|
-
filterFill: {
|
|
152
|
-
backgroundColor: colorVars['--color-overlay-pressed'],
|
|
153
|
-
},
|
|
154
|
-
// A ghost Button has no chrome at all, so the border is what puts the count
|
|
155
|
-
// in the same family as the unset selectors it stands in for. Left unfilled
|
|
156
|
-
// deliberately: the fill means "this control carries a value", and the count
|
|
157
|
-
// carries none of its own — it stands in for clauses that may or may not be
|
|
158
|
-
// set.
|
|
159
|
-
overflowChip: {
|
|
160
|
-
borderWidth: borderVars['--border-width'],
|
|
161
|
-
borderStyle: 'solid',
|
|
162
|
-
borderColor: colorVars['--color-border-emphasized'],
|
|
163
|
-
borderRadius: radiusVars['--radius-element'],
|
|
164
|
-
backgroundColor: colorVars['--color-background-surface'],
|
|
165
|
-
},
|
|
166
|
-
// Shrink-wrapped to the clauses actually on the row. As a flex item the
|
|
167
|
-
// list's basis is its unfolded content, which is wider than the slot, so it
|
|
168
|
-
// would otherwise settle at the slot's full width and strand the readout at
|
|
169
|
-
// the far edge with a gap where the folded clauses used to be. The list
|
|
170
|
-
// measures the slot, not itself, so sizing it to its visible children costs
|
|
171
|
-
// the fold nothing.
|
|
172
|
-
clauseList: {
|
|
173
|
-
flexGrow: 0,
|
|
174
|
-
flexShrink: 0,
|
|
175
|
-
width: 'max-content',
|
|
176
|
-
maxWidth: '100%',
|
|
177
|
-
},
|
|
178
|
-
// Takes back the width the slot held back for it, so the readout draws over
|
|
179
|
-
// the reserve and lands against the last clause. The gap to that clause is a
|
|
180
|
-
// margin rather than the row's `gap`, because a gap would fall on the
|
|
181
|
-
// measured side of the reserve and cost the clauses those pixels.
|
|
182
|
-
readout: {
|
|
183
|
-
flexShrink: 0,
|
|
184
|
-
whiteSpace: 'nowrap',
|
|
185
|
-
marginInlineStart: 8,
|
|
186
|
-
marginInlineEnd: -READOUT_RESERVE,
|
|
187
|
-
},
|
|
188
|
-
viewPanel: {
|
|
189
|
-
width: 320,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
9
|
+
import {MoreMenu} from '@astryxdesign/core/MoreMenu';
|
|
10
|
+
import {Stack} from '@astryxdesign/core/Layout';
|
|
11
|
+
import {Table} from '@astryxdesign/core/Table';
|
|
12
|
+
import {MagnifyingGlassIcon} from '@heroicons/react/24/outline';
|
|
192
13
|
|
|
193
14
|
export default function ToolbarTableFilter() {
|
|
194
15
|
const [search, setSearch] = useState('');
|
|
195
|
-
const [
|
|
196
|
-
const [
|
|
197
|
-
|
|
198
|
-
const hasFilters =
|
|
199
|
-
search !== '' || Object.values(clauses).some(value => value != null);
|
|
200
|
-
|
|
201
|
-
const clearAll = () => {
|
|
202
|
-
setSearch('');
|
|
203
|
-
setClauses({});
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// Search and every clause narrow one pass, so the table answers the whole
|
|
207
|
-
// bar rather than whichever control moved last.
|
|
208
|
-
const results = useMemo(() => {
|
|
209
|
-
const query = search.trim().toLowerCase();
|
|
210
|
-
return JOBS.filter(
|
|
211
|
-
row =>
|
|
212
|
-
(query === '' ||
|
|
213
|
-
`${row.job} ${row.customer}`.toLowerCase().includes(query)) &&
|
|
214
|
-
FIELDS.every(
|
|
215
|
-
field =>
|
|
216
|
-
clauses[field.key] == null || row[field.key] === clauses[field.key],
|
|
217
|
-
),
|
|
218
|
-
);
|
|
219
|
-
}, [search, clauses]);
|
|
220
|
-
|
|
221
|
-
// One flat array rather than inline JSX: OverflowList hands its renderer the
|
|
222
|
-
// indices of the clauses it had to hide, so the row and the folded panel have
|
|
223
|
-
// to read from the same list for those indices to mean anything.
|
|
224
|
-
const clauseControls = FIELDS.map(field => (
|
|
225
|
-
<Selector
|
|
226
|
-
key={field.key}
|
|
227
|
-
label={`${field.label} filter`}
|
|
228
|
-
isLabelHidden
|
|
229
|
-
placeholder={field.label}
|
|
230
|
-
size="sm"
|
|
231
|
-
hasClear
|
|
232
|
-
options={field.options}
|
|
233
|
-
value={clauses[field.key] ?? null}
|
|
234
|
-
xstyle={clauses[field.key] != null ? styles.filterFill : undefined}
|
|
235
|
-
onChange={value => setClauses(prev => ({...prev, [field.key]: value}))}
|
|
236
|
-
renderValue={option =>
|
|
237
|
-
`${field.label} is ${option.label ?? option.value}`
|
|
238
|
-
}
|
|
239
|
-
/>
|
|
240
|
-
));
|
|
241
|
-
|
|
242
|
-
const viewOptions = (
|
|
243
|
-
<VStack gap={3} xstyle={styles.viewPanel}>
|
|
244
|
-
<Heading level={3}>Columns</Heading>
|
|
245
|
-
<CheckboxList
|
|
246
|
-
label="Displayed columns"
|
|
247
|
-
isLabelHidden
|
|
248
|
-
density="compact"
|
|
249
|
-
value={columnKeys}
|
|
250
|
-
onChange={setColumnKeys}>
|
|
251
|
-
{COLUMNS.map(column => (
|
|
252
|
-
<CheckboxListItem
|
|
253
|
-
key={column.key}
|
|
254
|
-
value={column.key}
|
|
255
|
-
label={String(column.header)}
|
|
256
|
-
/>
|
|
257
|
-
))}
|
|
258
|
-
</CheckboxList>
|
|
259
|
-
</VStack>
|
|
260
|
-
);
|
|
16
|
+
const [status, setStatus] = useState<string | null>(null);
|
|
17
|
+
const [priority, setPriority] = useState<string | null>(null);
|
|
261
18
|
|
|
262
19
|
return (
|
|
263
|
-
|
|
264
|
-
// have to start on the same line, and the container publishes the padding
|
|
265
|
-
// both read — the toolbar pads to it, and the table bleeds edge to edge
|
|
266
|
-
// and compensates its outer cells back to it. Transparent and borderless,
|
|
267
|
-
// because whatever hosts this block already paints its own frame.
|
|
268
|
-
<Section variant="transparent" padding={2} width="100%" height="100%">
|
|
20
|
+
<Stack direction="vertical" style={{width: '100%'}}>
|
|
269
21
|
<Toolbar
|
|
270
|
-
label="
|
|
22
|
+
label="Table filters"
|
|
271
23
|
size="sm"
|
|
272
24
|
dividers={['bottom']}
|
|
273
25
|
startContent={
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
// is what stays, and it opens onto every clause.
|
|
312
|
-
minVisibleItems={0}
|
|
313
|
-
overflowRenderer={overflowItems => (
|
|
314
|
-
<Popover
|
|
315
|
-
placement="below"
|
|
316
|
-
alignment="start"
|
|
317
|
-
width={240}
|
|
318
|
-
label={`${overflowItems.length} more filters`}
|
|
319
|
-
content={
|
|
320
|
-
<VStack gap={2}>
|
|
321
|
-
{overflowItems.map(({child, index}) => (
|
|
322
|
-
<Stack key={index} direction="vertical">
|
|
323
|
-
{child}
|
|
324
|
-
</Stack>
|
|
325
|
-
))}
|
|
326
|
-
</VStack>
|
|
327
|
-
}>
|
|
328
|
-
<Button
|
|
329
|
-
label={`+${overflowItems.length}`}
|
|
330
|
-
tooltip={`${overflowItems.length} more filters`}
|
|
331
|
-
variant="ghost"
|
|
332
|
-
size="sm"
|
|
333
|
-
xstyle={styles.overflowChip}
|
|
334
|
-
/>
|
|
335
|
-
</Popover>
|
|
336
|
-
)}>
|
|
337
|
-
{clauseControls}
|
|
338
|
-
</OverflowList>
|
|
339
|
-
|
|
340
|
-
{/* Inside the slot rather than beside it: a sibling would sit
|
|
341
|
-
after the slot, and the slot spans the row's leftover, so the
|
|
342
|
-
readout would land at the trailing edge however few clauses
|
|
343
|
-
were showing. In here it follows the clauses, and the reserve
|
|
344
|
-
is what stops the list from spending the width it needs. */}
|
|
345
|
-
<HStack
|
|
346
|
-
gap={2}
|
|
347
|
-
vAlign="center"
|
|
348
|
-
wrap="nowrap"
|
|
349
|
-
xstyle={styles.readout}>
|
|
350
|
-
<Text type="supporting" color="secondary">
|
|
351
|
-
{results.length} of {JOBS.length}
|
|
352
|
-
</Text>
|
|
353
|
-
{hasFilters && (
|
|
354
|
-
<>
|
|
355
|
-
<Text type="supporting" color="secondary">
|
|
356
|
-
•
|
|
357
|
-
</Text>
|
|
358
|
-
{/* Href-less, so Link renders a button: this resets the
|
|
359
|
-
filters, it does not navigate. */}
|
|
360
|
-
<Link type="supporting" onClick={clearAll}>
|
|
361
|
-
Clear all
|
|
362
|
-
</Link>
|
|
363
|
-
</>
|
|
364
|
-
)}
|
|
365
|
-
</HStack>
|
|
366
|
-
</StackItem>
|
|
367
|
-
{/* View options closes the row: it acts on the table, not on the
|
|
368
|
-
filter set, so it stands apart from the clauses. */}
|
|
369
|
-
<Popover
|
|
370
|
-
placement="below"
|
|
371
|
-
alignment="end"
|
|
372
|
-
label="View options"
|
|
373
|
-
content={viewOptions}>
|
|
374
|
-
<Button
|
|
375
|
-
label="View options"
|
|
376
|
-
tooltip="View options"
|
|
377
|
-
isIconOnly
|
|
378
|
-
variant="ghost"
|
|
379
|
-
size="sm"
|
|
380
|
-
icon={<Icon icon={Columns3Cog} size="sm" color="secondary" />}
|
|
381
|
-
/>
|
|
382
|
-
</Popover>
|
|
383
|
-
</HStack>
|
|
26
|
+
<>
|
|
27
|
+
<TextInput
|
|
28
|
+
label="Search"
|
|
29
|
+
isLabelHidden
|
|
30
|
+
placeholder="Search..."
|
|
31
|
+
value={search}
|
|
32
|
+
onChange={setSearch}
|
|
33
|
+
startIcon={MagnifyingGlassIcon}
|
|
34
|
+
/>
|
|
35
|
+
<Selector
|
|
36
|
+
label="Status"
|
|
37
|
+
isLabelHidden
|
|
38
|
+
placeholder="Status"
|
|
39
|
+
hasClear
|
|
40
|
+
value={status}
|
|
41
|
+
onChange={setStatus}
|
|
42
|
+
options={['Open', 'In progress', 'Done']}
|
|
43
|
+
/>
|
|
44
|
+
<Selector
|
|
45
|
+
label="Priority"
|
|
46
|
+
isLabelHidden
|
|
47
|
+
placeholder="Priority"
|
|
48
|
+
hasClear
|
|
49
|
+
value={priority}
|
|
50
|
+
onChange={setPriority}
|
|
51
|
+
options={['High', 'Medium', 'Low']}
|
|
52
|
+
/>
|
|
53
|
+
</>
|
|
54
|
+
}
|
|
55
|
+
endContent={
|
|
56
|
+
<MoreMenu
|
|
57
|
+
items={[
|
|
58
|
+
{label: 'Compact view'},
|
|
59
|
+
{label: 'Comfortable view'},
|
|
60
|
+
{label: 'Export CSV'},
|
|
61
|
+
]}
|
|
62
|
+
/>
|
|
384
63
|
}
|
|
385
64
|
/>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
65
|
+
<Table
|
|
66
|
+
idKey="id"
|
|
67
|
+
columns={[
|
|
68
|
+
{key: 'task', header: 'Task'},
|
|
69
|
+
{key: 'status', header: 'Status'},
|
|
70
|
+
{key: 'priority', header: 'Priority'},
|
|
71
|
+
]}
|
|
72
|
+
data={[
|
|
73
|
+
{id: '1', task: 'Fix login bug', status: 'Open', priority: 'High'},
|
|
74
|
+
{
|
|
75
|
+
id: '2',
|
|
76
|
+
task: 'Update docs',
|
|
77
|
+
status: 'In progress',
|
|
78
|
+
priority: 'Medium',
|
|
79
|
+
},
|
|
80
|
+
{id: '3', task: 'Add unit tests', status: 'Open', priority: 'Low'},
|
|
81
|
+
]}
|
|
82
|
+
/>
|
|
83
|
+
</Stack>
|
|
402
84
|
);
|
|
403
85
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.6.3
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"displayName": "CLI",
|
|
5
5
|
"description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -100,10 +100,10 @@
|
|
|
100
100
|
"zod": "^4.4.3"
|
|
101
101
|
},
|
|
102
102
|
"peerDependencies": {
|
|
103
|
-
"@astryxdesign/charts": "
|
|
104
|
-
"@astryxdesign/core": "
|
|
105
|
-
"@astryxdesign/lab": "
|
|
106
|
-
"@astryxdesign/theme-neutral": "
|
|
103
|
+
"@astryxdesign/charts": "*",
|
|
104
|
+
"@astryxdesign/core": "*",
|
|
105
|
+
"@astryxdesign/lab": "*",
|
|
106
|
+
"@astryxdesign/theme-neutral": "*",
|
|
107
107
|
"gpt-tokenizer": "^3.4.0"
|
|
108
108
|
},
|
|
109
109
|
"peerDependenciesMeta": {
|
|
@@ -121,10 +121,10 @@
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
|
-
"@astryxdesign/charts": "
|
|
125
|
-
"@astryxdesign/core": "
|
|
126
|
-
"@astryxdesign/lab": "
|
|
127
|
-
"@astryxdesign/theme-neutral": "
|
|
124
|
+
"@astryxdesign/charts": "*",
|
|
125
|
+
"@astryxdesign/core": "*",
|
|
126
|
+
"@astryxdesign/lab": "*",
|
|
127
|
+
"@astryxdesign/theme-neutral": "*",
|
|
128
128
|
"@heroicons/react": "^2.2.0",
|
|
129
129
|
"@stylexjs/stylex": "^0.19.0",
|
|
130
130
|
"@types/babel__core": "^7.20.5",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Timer',
|
|
7
|
-
name: 'Timer — Formats',
|
|
8
|
-
displayName: 'Timer — Formats',
|
|
9
|
-
description:
|
|
10
|
-
'Elapsed compact units and stopwatch clock notation shown from the same start time.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 16 / 9,
|
|
13
|
-
componentsUsed: ['Timer', 'Layout', 'Text'],
|
|
14
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {useState} from 'react';
|
|
6
|
-
import {Timer} from '@astryxdesign/core/Timer';
|
|
7
|
-
import {Stack} from '@astryxdesign/core/Layout';
|
|
8
|
-
import {Text} from '@astryxdesign/core/Text';
|
|
9
|
-
|
|
10
|
-
export default function TimerFormats() {
|
|
11
|
-
const [startedAt] = useState(() => Date.now() - 3_753_000);
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Stack direction="vertical" gap={3}>
|
|
15
|
-
<Stack direction="horizontal" gap={3} vAlign="center">
|
|
16
|
-
<Text type="supporting" color="secondary">
|
|
17
|
-
Elapsed
|
|
18
|
-
</Text>
|
|
19
|
-
<Timer startTime={startedAt} type="body" color="primary" />
|
|
20
|
-
</Stack>
|
|
21
|
-
<Stack direction="horizontal" gap={3} vAlign="center">
|
|
22
|
-
<Text type="supporting" color="secondary">
|
|
23
|
-
Clock
|
|
24
|
-
</Text>
|
|
25
|
-
<Timer
|
|
26
|
-
format="clock"
|
|
27
|
-
startTime={startedAt}
|
|
28
|
-
type="body"
|
|
29
|
-
color="primary"
|
|
30
|
-
/>
|
|
31
|
-
</Stack>
|
|
32
|
-
</Stack>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Timer',
|
|
7
|
-
name: 'Timer — Inline',
|
|
8
|
-
displayName: 'Timer — Inline',
|
|
9
|
-
description:
|
|
10
|
-
'A Timer composed into status copy while inheriting the surrounding typography.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 16 / 9,
|
|
13
|
-
componentsUsed: ['Timer', 'Text'],
|
|
14
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {Timer} from '@astryxdesign/core/Timer';
|
|
6
|
-
import {Text} from '@astryxdesign/core/Text';
|
|
7
|
-
|
|
8
|
-
export default function TimerInline() {
|
|
9
|
-
return (
|
|
10
|
-
<Text type="body" color="primary">
|
|
11
|
-
Processing for <Timer type="inherit" color="inherit" />
|
|
12
|
-
</Text>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Timer',
|
|
7
|
-
name: 'Timer',
|
|
8
|
-
displayName: 'Timer',
|
|
9
|
-
isReady: true,
|
|
10
|
-
aspectRatio: 16 / 9,
|
|
11
|
-
isShowcase: true,
|
|
12
|
-
componentsUsed: ['Timer', 'Layout', 'Text'],
|
|
13
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {useState} from 'react';
|
|
6
|
-
import {Timer} from '@astryxdesign/core/Timer';
|
|
7
|
-
import {Stack} from '@astryxdesign/core/Layout';
|
|
8
|
-
import {Text} from '@astryxdesign/core/Text';
|
|
9
|
-
|
|
10
|
-
export default function TimerShowcase() {
|
|
11
|
-
const [startedAt] = useState(() => Date.now() - 3_753_000);
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Stack direction="vertical" gap={4}>
|
|
15
|
-
<Text type="large" color="primary" weight="semibold">
|
|
16
|
-
Processing
|
|
17
|
-
</Text>
|
|
18
|
-
<Stack direction="horizontal" gap={6} vAlign="center">
|
|
19
|
-
<Stack direction="vertical" gap={1}>
|
|
20
|
-
<Text type="supporting" color="secondary">
|
|
21
|
-
Elapsed
|
|
22
|
-
</Text>
|
|
23
|
-
<Timer
|
|
24
|
-
startTime={startedAt}
|
|
25
|
-
type="body"
|
|
26
|
-
size="xl"
|
|
27
|
-
color="primary"
|
|
28
|
-
weight="semibold"
|
|
29
|
-
/>
|
|
30
|
-
</Stack>
|
|
31
|
-
<Stack direction="vertical" gap={1}>
|
|
32
|
-
<Text type="supporting" color="secondary">
|
|
33
|
-
Clock
|
|
34
|
-
</Text>
|
|
35
|
-
<Timer
|
|
36
|
-
format="clock"
|
|
37
|
-
startTime={startedAt}
|
|
38
|
-
type="body"
|
|
39
|
-
size="xl"
|
|
40
|
-
color="primary"
|
|
41
|
-
weight="semibold"
|
|
42
|
-
/>
|
|
43
|
-
</Stack>
|
|
44
|
-
</Stack>
|
|
45
|
-
</Stack>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Timer',
|
|
7
|
-
name: 'Timer — Typography',
|
|
8
|
-
displayName: 'Timer — Typography',
|
|
9
|
-
description:
|
|
10
|
-
'Timer using its Timestamp-matched default typography and an emphasized override.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 16 / 9,
|
|
13
|
-
componentsUsed: ['Timer', 'Layout', 'Text'],
|
|
14
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {useState} from 'react';
|
|
6
|
-
import {Timer} from '@astryxdesign/core/Timer';
|
|
7
|
-
import {Stack} from '@astryxdesign/core/Layout';
|
|
8
|
-
import {Text} from '@astryxdesign/core/Text';
|
|
9
|
-
|
|
10
|
-
export default function TimerTypography() {
|
|
11
|
-
const [startedAt] = useState(() => Date.now() - 128_000);
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Stack direction="vertical" gap={3}>
|
|
15
|
-
<Text type="supporting" color="secondary">
|
|
16
|
-
Default
|
|
17
|
-
</Text>
|
|
18
|
-
<Timer startTime={startedAt} />
|
|
19
|
-
<Text type="supporting" color="secondary">
|
|
20
|
-
Emphasized
|
|
21
|
-
</Text>
|
|
22
|
-
<Timer
|
|
23
|
-
startTime={startedAt}
|
|
24
|
-
type="body"
|
|
25
|
-
size="xl"
|
|
26
|
-
color="primary"
|
|
27
|
-
weight="semibold"
|
|
28
|
-
/>
|
|
29
|
-
</Stack>
|
|
30
|
-
);
|
|
31
|
-
}
|