noecosystem-design 0.1.2 → 0.1.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/apps/showcase/src/catalog/catalog-index.tsx +5 -5
- package/apps/showcase/src/catalog/catalog-shell.tsx +7 -2
- package/apps/storybook/stories/catalog/calendar.stories.tsx +3 -1
- package/apps/storybook/stories/catalog/date-picker.stories.tsx +5 -1
- package/docs/design-system/inventory.md +0 -1
- package/package.json +2 -2
- package/packages/ai-ui/src/activity-feed.tsx +1 -2
- package/packages/ai-ui/src/agent-composer.tsx +1 -1
- package/packages/ai-ui/src/agent-message.tsx +1 -1
- package/packages/ai-ui/src/agent-plan.tsx +1 -1
- package/packages/ai-ui/src/agent-workspace.tsx +1 -2
- package/packages/ai-ui/src/approval-request.tsx +1 -1
- package/packages/ai-ui/src/run-inspector.tsx +1 -1
- package/packages/ai-ui/src/tool-call.tsx +1 -1
- package/packages/data-ui/src/activity-gauge.tsx +1 -1
- package/packages/data-ui/src/chart-frame.tsx +1 -1
- package/packages/data-ui/src/chart.tsx +1 -2
- package/packages/data-ui/src/dashboard-shell.tsx +1 -2
- package/packages/data-ui/src/data-table.tsx +1 -1
- package/packages/data-ui/src/filter-bar.tsx +1 -2
- package/packages/data-ui/src/metric-card.tsx +1 -1
- package/packages/data-ui/src/pagination.tsx +1 -3
- package/packages/data-ui/src/pie-chart.tsx +1 -1
- package/packages/data-ui/src/radar-chart.tsx +1 -1
- package/packages/design-tokens/src/palette.ts +4 -4
- package/packages/design-tokens/src/tokens.css +0 -6
- package/packages/registry/catalog-index.json +1 -1
- package/packages/registry/component-audit.json +1 -1
- package/packages/registry/docs-index.json +135 -403
- package/packages/registry/manifest.json +1642 -6110
- package/packages/registry/r/activity-feed.json +9 -32
- package/packages/registry/r/agent-composer.json +9 -34
- package/packages/registry/r/agent-message.json +9 -32
- package/packages/registry/r/agent-plan.json +9 -32
- package/packages/registry/r/agent-workspace.json +9 -32
- package/packages/registry/r/alert.json +9 -33
- package/packages/registry/r/app-frame.json +9 -32
- package/packages/registry/r/approval-request.json +9 -34
- package/packages/registry/r/badge.json +9 -33
- package/packages/registry/r/bidi-text.json +7 -25
- package/packages/registry/r/bottom-navigation.json +9 -32
- package/packages/registry/r/button.json +7 -29
- package/packages/registry/r/calendar.json +10 -37
- package/packages/registry/r/card.json +9 -32
- package/packages/registry/r/chart-frame.json +9 -32
- package/packages/registry/r/chart.json +8 -30
- package/packages/registry/r/code-block.json +9 -32
- package/packages/registry/r/context-menu.json +8 -36
- package/packages/registry/r/dashboard-01.json +7 -23
- package/packages/registry/r/dashboard-02.json +6 -20
- package/packages/registry/r/dashboard-shell.json +9 -32
- package/packages/registry/r/data-list.json +9 -32
- package/packages/registry/r/data-table.json +9 -32
- package/packages/registry/r/date-picker.json +10 -37
- package/packages/registry/r/dialog.json +11 -45
- package/packages/registry/r/direction-provider.json +6 -21
- package/packages/registry/r/drawer.json +10 -36
- package/packages/registry/r/dropdown.json +9 -37
- package/packages/registry/r/empty-state.json +9 -32
- package/packages/registry/r/error-state.json +9 -32
- package/packages/registry/r/fab.json +9 -34
- package/packages/registry/r/featured-icon.json +7 -29
- package/packages/registry/r/filter-bar.json +10 -35
- package/packages/registry/r/gradient-picker.json +7 -24
- package/packages/registry/r/header-navigation.json +9 -32
- package/packages/registry/r/hero-header.json +7 -25
- package/packages/registry/r/icon-system.json +8 -28
- package/packages/registry/r/image-picker.json +7 -24
- package/packages/registry/r/inline-cta.json +9 -32
- package/packages/registry/r/input.json +9 -33
- package/packages/registry/r/landing-page.json +6 -21
- package/packages/registry/r/login-page.json +9 -35
- package/packages/registry/r/marketing-header.json +8 -26
- package/packages/registry/r/menu.json +9 -34
- package/packages/registry/r/messaging.json +9 -33
- package/packages/registry/r/metric-card.json +9 -32
- package/packages/registry/r/mobile-screen.json +9 -32
- package/packages/registry/r/not-found.json +7 -25
- package/packages/registry/r/page-header.json +9 -32
- package/packages/registry/r/pagination.json +10 -37
- package/packages/registry/r/progress-steps.json +9 -33
- package/packages/registry/r/run-inspector.json +9 -32
- package/packages/registry/r/section-header.json +9 -32
- package/packages/registry/r/settings-01.json +5 -19
- package/packages/registry/r/settings-02.json +5 -19
- package/packages/registry/r/settings-page.json +9 -32
- package/packages/registry/r/sidebar-navigation.json +9 -32
- package/packages/registry/r/sign-in-form.json +9 -34
- package/packages/registry/r/skeleton.json +9 -32
- package/packages/registry/r/spinner.json +9 -32
- package/packages/registry/r/tabs.json +9 -34
- package/packages/registry/r/textarea.json +9 -33
- package/packages/registry/r/tool-call.json +9 -32
- package/packages/registry/r/tooltip.json +9 -33
- package/packages/registry/r/utility-button.json +9 -37
- package/packages/registry/r/workflow-canvas.json +9 -32
- package/packages/registry/r/workflow-node.json +9 -32
- package/packages/registry/registry.json +232 -937
- package/packages/registry/search-index.json +579 -2194
- package/packages/ui/package.json +4 -1
- package/packages/ui/src/date-picker.browser.test.tsx +1 -1
- package/packages/ui/src/date-picker.tsx +1 -2
- package/packages/ui/src/gradient-picker.tsx +6 -2
- package/packages/ui/src/theme-provider.browser.test.tsx +12 -4
- package/packages/ui/src/theme-provider.tsx +19 -5
- package/packages/workflow-ui/src/workflow-canvas.tsx +1 -1
- package/packages/workflow-ui/src/workflow-node.tsx +1 -1
- package/scripts/enrich-registry-payloads.mjs +9 -3
- package/scripts/fix-registry-closure.mjs +2 -1
- package/scripts/generate-manifest.mjs +5 -1
- package/scripts/validate-manifest.mjs +25 -8
- package/scripts/verify-registry-consumer.mjs +33 -7
- package/tests/e2e/catalog-typography.spec.ts +5 -2
- package/tsconfig.base.json +17 -51
package/packages/ui/package.json
CHANGED
|
@@ -96,8 +96,7 @@ export function DatePicker({
|
|
|
96
96
|
setPopoverStyle({
|
|
97
97
|
position: 'fixed',
|
|
98
98
|
top: `${rect.bottom + 8}px`,
|
|
99
|
-
|
|
100
|
-
right: isRtl ? `${window.innerWidth - rect.right}px` : 'auto',
|
|
99
|
+
insetInlineStart: `${isRtl ? window.innerWidth - rect.right : rect.left}px`,
|
|
101
100
|
zIndex: 'var(--noe-z-index-overlay, 50)',
|
|
102
101
|
});
|
|
103
102
|
};
|
|
@@ -42,14 +42,18 @@ export function GradientPicker({
|
|
|
42
42
|
aria-label="Start color"
|
|
43
43
|
type="color"
|
|
44
44
|
defaultValue={GRADIENT_START}
|
|
45
|
-
onChange={(e) =>
|
|
45
|
+
onChange={(e) =>
|
|
46
|
+
onValueChange?.(`linear-gradient(90deg, ${e.target.value}, ${GRADIENT_END})`)
|
|
47
|
+
}
|
|
46
48
|
className="size-8 rounded-md border border-border"
|
|
47
49
|
/>
|
|
48
50
|
<input
|
|
49
51
|
aria-label="End color"
|
|
50
52
|
type="color"
|
|
51
53
|
defaultValue={GRADIENT_END}
|
|
52
|
-
onChange={(e) =>
|
|
54
|
+
onChange={(e) =>
|
|
55
|
+
onValueChange?.(`linear-gradient(90deg, ${GRADIENT_START}, ${e.target.value})`)
|
|
56
|
+
}
|
|
53
57
|
className="size-8 rounded-md border border-border"
|
|
54
58
|
/>
|
|
55
59
|
<input
|
|
@@ -10,7 +10,9 @@ function PaletteProbe({ storageKey }: { storageKey?: string }) {
|
|
|
10
10
|
return (
|
|
11
11
|
<div>
|
|
12
12
|
<span data-testid="palette">{palette}</span>
|
|
13
|
-
<button type="button" onClick={() => setPalette('graphite' as never)}>
|
|
13
|
+
<button type="button" onClick={() => setPalette('graphite' as never)}>
|
|
14
|
+
set graphite
|
|
15
|
+
</button>
|
|
14
16
|
{storageKey && <span data-testid="storageKey">{storageKey}</span>}
|
|
15
17
|
</div>
|
|
16
18
|
);
|
|
@@ -26,7 +28,9 @@ test('default Graphite with no preference', async () => {
|
|
|
26
28
|
</ThemeProvider>,
|
|
27
29
|
);
|
|
28
30
|
await expect.element(screen.getByTestId('palette')).toHaveTextContent('graphite');
|
|
29
|
-
await expect
|
|
31
|
+
await expect
|
|
32
|
+
.poll(() => document.documentElement.getAttribute('data-noe-palette'))
|
|
33
|
+
.toBe('graphite');
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
test('valid stored preference restoration', async () => {
|
|
@@ -49,7 +53,9 @@ test('invalid storage and cookie fallback to Graphite', async () => {
|
|
|
49
53
|
);
|
|
50
54
|
// Should fallback to graphite
|
|
51
55
|
await expect.element(screen.getByTestId('palette')).toHaveTextContent('graphite');
|
|
52
|
-
await expect
|
|
56
|
+
await expect
|
|
57
|
+
.poll(() => document.documentElement.getAttribute('data-noe-palette'))
|
|
58
|
+
.toBe('graphite');
|
|
53
59
|
});
|
|
54
60
|
|
|
55
61
|
test('custom paletteStorageKey is honored', async () => {
|
|
@@ -84,7 +90,9 @@ test('palette/theme independence in light and dark modes', async () => {
|
|
|
84
90
|
</ThemeProvider>,
|
|
85
91
|
);
|
|
86
92
|
await expect.element(screen.getByTestId('palette')).toHaveTextContent('graphite');
|
|
87
|
-
await expect
|
|
93
|
+
await expect
|
|
94
|
+
.poll(() => document.documentElement.getAttribute('data-noe-palette'))
|
|
95
|
+
.toBe('graphite');
|
|
88
96
|
await expect.poll(() => document.documentElement.dataset.theme).toBe('light');
|
|
89
97
|
await expect.element(screen.getByTestId('palette')).toHaveTextContent('graphite');
|
|
90
98
|
});
|
|
@@ -160,8 +160,12 @@ function applyThemeToDocument(theme: ResolvedTheme) {
|
|
|
160
160
|
root.style.colorScheme = theme;
|
|
161
161
|
const meta = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]');
|
|
162
162
|
if (meta) {
|
|
163
|
-
const lightFallback =
|
|
164
|
-
|
|
163
|
+
const lightFallback =
|
|
164
|
+
(tokens as unknown as { primitive: { color: { paper: Record<string, string> } } }).primitive
|
|
165
|
+
?.color?.paper?.['100'] ?? '#f3f0ea';
|
|
166
|
+
const darkFallback =
|
|
167
|
+
(tokens as unknown as { primitive: { color: { ink: Record<string, string> } } }).primitive
|
|
168
|
+
?.color?.ink?.['950'] ?? '#252423';
|
|
165
169
|
const light = meta.getAttribute('data-theme-light') ?? lightFallback;
|
|
166
170
|
const dark = meta.getAttribute('data-theme-dark') ?? darkFallback;
|
|
167
171
|
meta.setAttribute('content', theme === 'light' ? light : dark);
|
|
@@ -202,7 +206,8 @@ export function ThemeProvider({
|
|
|
202
206
|
});
|
|
203
207
|
|
|
204
208
|
const [palette, setPaletteState] = React.useState<Palette>(() => {
|
|
205
|
-
if (typeof window === 'undefined')
|
|
209
|
+
if (typeof window === 'undefined')
|
|
210
|
+
return isPalette(defaultPalette) ? defaultPalette : DEFAULT_PALETTE;
|
|
206
211
|
const stored = readStoredPalette(paletteStorageKey);
|
|
207
212
|
if (stored && isPalette(stored)) return stored;
|
|
208
213
|
if (isPalette(defaultPalette)) return defaultPalette;
|
|
@@ -307,7 +312,12 @@ export function ThemeProvider({
|
|
|
307
312
|
|
|
308
313
|
React.useEffect(() => {
|
|
309
314
|
const stored = readStoredPalette(paletteStorageKey);
|
|
310
|
-
const initialPalette =
|
|
315
|
+
const initialPalette =
|
|
316
|
+
stored && isPalette(stored)
|
|
317
|
+
? stored
|
|
318
|
+
: isPalette(defaultPalette)
|
|
319
|
+
? defaultPalette
|
|
320
|
+
: DEFAULT_PALETTE;
|
|
311
321
|
const validated = isPalette(initialPalette) ? initialPalette : DEFAULT_PALETTE;
|
|
312
322
|
setPaletteState(validated);
|
|
313
323
|
applyPaletteToDocument(validated);
|
|
@@ -318,7 +328,11 @@ export function ThemeProvider({
|
|
|
318
328
|
|
|
319
329
|
React.useEffect(() => {
|
|
320
330
|
const onStorage = (event: StorageEvent) => {
|
|
321
|
-
if (
|
|
331
|
+
if (
|
|
332
|
+
event.key === paletteStorageKey ||
|
|
333
|
+
event.key === PALETTE_STORAGE_KEY ||
|
|
334
|
+
event.key === PALETTE_COOKIE_KEY
|
|
335
|
+
) {
|
|
322
336
|
if (isPalette(event.newValue)) {
|
|
323
337
|
setPaletteState(event.newValue as Palette);
|
|
324
338
|
applyPaletteToDocument(event.newValue as Palette);
|
|
@@ -46,9 +46,15 @@ for (const item of manifest.items.filter(
|
|
|
46
46
|
? ['DirectionProvider']
|
|
47
47
|
: [],
|
|
48
48
|
// Dependencies — merge manifest and payload, keeping externally installable npm packages; workspace @noe/* are satisfied via included files/registryDependencies
|
|
49
|
-
registryDependencies: [
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
registryDependencies: [
|
|
50
|
+
...new Set([...(item.registryDependencies || []), ...(payload.registryDependencies || [])]),
|
|
51
|
+
],
|
|
52
|
+
dependencies: [
|
|
53
|
+
...new Set([...(item.dependencies || []), ...(payload.dependencies || [])]),
|
|
54
|
+
].filter((d) => !d.startsWith('@noe/')),
|
|
55
|
+
peerDependencies: [
|
|
56
|
+
...new Set([...(item.peerDependencies || []), ...(payload.peerDependencies || [])]),
|
|
57
|
+
],
|
|
52
58
|
// RTL/i18n
|
|
53
59
|
rtl: item.internationalization?.rtl || 'required',
|
|
54
60
|
i18n: {
|
|
@@ -7,7 +7,8 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
|
7
7
|
function extractImports(content) {
|
|
8
8
|
const imports = [];
|
|
9
9
|
for (const m of content.matchAll(/from\s+['"]([^'"]+)['"]/g)) imports.push(m[1]);
|
|
10
|
-
for (const m of content.matchAll(/import\s+['"]([^'"]+)['"]/g))
|
|
10
|
+
for (const m of content.matchAll(/import\s+['"]([^'"]+)['"]/g))
|
|
11
|
+
if (!imports.includes(m[1])) imports.push(m[1]);
|
|
11
12
|
return imports;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -764,7 +764,11 @@ function defaultEnrichment(auditItem) {
|
|
|
764
764
|
deps.push('@noe/icons');
|
|
765
765
|
if (auditItem.id === 'filter-bar') registryDeps.push('input');
|
|
766
766
|
// Hard-coded icon consumers discovered via audit (calendar, inline-cta, date-picker)
|
|
767
|
-
if (
|
|
767
|
+
if (
|
|
768
|
+
auditItem.id === 'calendar' ||
|
|
769
|
+
auditItem.id === 'inline-cta' ||
|
|
770
|
+
auditItem.id === 'date-picker'
|
|
771
|
+
) {
|
|
768
772
|
if (!deps.includes('@noe/icons')) deps.push('@noe/icons');
|
|
769
773
|
}
|
|
770
774
|
|
|
@@ -292,7 +292,9 @@ if (errors === 0) pass('semantic search fields');
|
|
|
292
292
|
// 13. Source-file and payload existence
|
|
293
293
|
{
|
|
294
294
|
let missing = 0;
|
|
295
|
-
for (const item of manifest.items.filter(
|
|
295
|
+
for (const item of manifest.items.filter(
|
|
296
|
+
(i) => i.status === 'available' || i.status === 'partial',
|
|
297
|
+
)) {
|
|
296
298
|
if (!item.registryItem) {
|
|
297
299
|
fail(`available/partial ${item.id} missing registryItem`);
|
|
298
300
|
errors++;
|
|
@@ -323,7 +325,9 @@ if (errors === 0) pass('semantic search fields');
|
|
|
323
325
|
// 14. Registry payload closure (relative imports must be included)
|
|
324
326
|
{
|
|
325
327
|
let closureErrors = 0;
|
|
326
|
-
for (const item of manifest.items.filter(
|
|
328
|
+
for (const item of manifest.items.filter(
|
|
329
|
+
(i) => i.status === 'available' || i.status === 'partial',
|
|
330
|
+
)) {
|
|
327
331
|
if (!item.registryItem) continue;
|
|
328
332
|
const payloadPath = path.join(root, `packages/registry/r/${item.registryItem}.json`);
|
|
329
333
|
let payload;
|
|
@@ -375,7 +379,9 @@ if (errors === 0) pass('semantic search fields');
|
|
|
375
379
|
}
|
|
376
380
|
});
|
|
377
381
|
// For simplicity, if not in current payload, check if it's in any other payload that is a dependency (we already include via files)
|
|
378
|
-
fail(
|
|
382
|
+
fail(
|
|
383
|
+
`closure: ${item.registryItem} ${f.path} imports '${imp}' -> ${resolved} not in payload`,
|
|
384
|
+
);
|
|
379
385
|
errors++;
|
|
380
386
|
closureErrors++;
|
|
381
387
|
}
|
|
@@ -390,7 +396,9 @@ if (errors === 0) pass('semantic search fields');
|
|
|
390
396
|
let missingStory = 0;
|
|
391
397
|
const storyFiles = new Set();
|
|
392
398
|
// Collect story ids from filesystem (reusing earlier logic would duplicate, but we check file existence directly)
|
|
393
|
-
for (const item of manifest.items.filter(
|
|
399
|
+
for (const item of manifest.items.filter(
|
|
400
|
+
(i) => i.status === 'available' || i.status === 'partial',
|
|
401
|
+
)) {
|
|
394
402
|
if (!item.storyId) {
|
|
395
403
|
fail(`available/partial ${item.id} missing storyId`);
|
|
396
404
|
errors++;
|
|
@@ -417,14 +425,18 @@ if (errors === 0) pass('semantic search fields');
|
|
|
417
425
|
// 16. Install command correctness
|
|
418
426
|
{
|
|
419
427
|
let badInstall = 0;
|
|
420
|
-
for (const item of manifest.items.filter(
|
|
428
|
+
for (const item of manifest.items.filter(
|
|
429
|
+
(i) => i.status === 'available' || i.status === 'partial',
|
|
430
|
+
)) {
|
|
421
431
|
if (!item.registryItem) continue;
|
|
422
432
|
const payloadPath = path.join(root, `packages/registry/r/${item.registryItem}.json`);
|
|
423
433
|
try {
|
|
424
434
|
const payload = await json(payloadPath);
|
|
425
435
|
const expected = `pnpm dlx shadcn@latest add @noe/${item.registryItem}`;
|
|
426
436
|
if (payload.install !== expected) {
|
|
427
|
-
fail(
|
|
437
|
+
fail(
|
|
438
|
+
`install command mismatch for ${item.registryItem}: expected "${expected}" got "${payload.install}"`,
|
|
439
|
+
);
|
|
428
440
|
errors++;
|
|
429
441
|
badInstall++;
|
|
430
442
|
}
|
|
@@ -443,7 +455,9 @@ if (errors === 0) pass('semantic search fields');
|
|
|
443
455
|
errors++;
|
|
444
456
|
plannedLeak++;
|
|
445
457
|
}
|
|
446
|
-
const rPath = item.registryItem
|
|
458
|
+
const rPath = item.registryItem
|
|
459
|
+
? path.join(root, `packages/registry/r/${item.registryItem}.json`)
|
|
460
|
+
: null;
|
|
447
461
|
if (rPath) {
|
|
448
462
|
try {
|
|
449
463
|
await stat(rPath);
|
|
@@ -462,7 +476,10 @@ if (errors === 0) pass('semantic search fields');
|
|
|
462
476
|
// This check ensures manifest correctly marks preview contract via status
|
|
463
477
|
let badPreview = 0;
|
|
464
478
|
for (const item of manifest.items) {
|
|
465
|
-
if (
|
|
479
|
+
if (
|
|
480
|
+
item.status === 'planned' &&
|
|
481
|
+
item.examples.some((e) => e.files.some((f) => f.includes('stories')))
|
|
482
|
+
) {
|
|
466
483
|
// Planned items should not have interactive story files that imply implementation
|
|
467
484
|
// We allow story files for planned only if they are spec placeholders — currently all planned share generic stories, so we skip
|
|
468
485
|
}
|
|
@@ -160,11 +160,22 @@ async function testConsumer({ name, rsc, items }) {
|
|
|
160
160
|
await run('pnpm', ['install'], { cwd: consumer });
|
|
161
161
|
|
|
162
162
|
// Batch install all items in one shadcn invocation (serial but batched for speed) — still verifies every payload individually
|
|
163
|
-
console.log(
|
|
163
|
+
console.log(
|
|
164
|
+
`\n[${name}] Installing ${items.length} payloads: ${items.slice(0, 3).join(', ')}...`,
|
|
165
|
+
);
|
|
164
166
|
try {
|
|
165
167
|
const { stdout, stderr } = await run(
|
|
166
168
|
'pnpm',
|
|
167
|
-
[
|
|
169
|
+
[
|
|
170
|
+
'dlx',
|
|
171
|
+
'shadcn@latest',
|
|
172
|
+
'add',
|
|
173
|
+
...items.map((i) => `@noe/${i}`),
|
|
174
|
+
'--yes',
|
|
175
|
+
'--overwrite',
|
|
176
|
+
'--cwd',
|
|
177
|
+
consumer,
|
|
178
|
+
],
|
|
168
179
|
{ cwd: root },
|
|
169
180
|
);
|
|
170
181
|
if (stdout) process.stdout.write(stdout);
|
|
@@ -180,11 +191,18 @@ async function testConsumer({ name, rsc, items }) {
|
|
|
180
191
|
const files = await walk(consumer);
|
|
181
192
|
let payloadCheck;
|
|
182
193
|
try {
|
|
183
|
-
payloadCheck = JSON.parse(
|
|
194
|
+
payloadCheck = JSON.parse(
|
|
195
|
+
await readFile(path.join(root, `packages/registry/r/${item}.json`), 'utf8'),
|
|
196
|
+
);
|
|
184
197
|
} catch {}
|
|
185
|
-
const expectedBasenames = payloadCheck
|
|
198
|
+
const expectedBasenames = payloadCheck
|
|
199
|
+
? payloadCheck.files.map((f) => path.basename(f.path))
|
|
200
|
+
: [item];
|
|
186
201
|
const found = files.find((f) => expectedBasenames.some((b) => f.endsWith(b)));
|
|
187
|
-
assert.ok(
|
|
202
|
+
assert.ok(
|
|
203
|
+
found,
|
|
204
|
+
`[${name}] shadcn did not install ${item}; expected one of ${expectedBasenames.join(', ')}, found: ${files.slice(0, 30).join(', ')}`,
|
|
205
|
+
);
|
|
188
206
|
console.log(`[${name}] Verified ${item} -> ${found}`);
|
|
189
207
|
for (const pf of payloadCheck?.files || []) {
|
|
190
208
|
const targetPath = pf.target || pf.path;
|
|
@@ -231,7 +249,10 @@ async function testConsumer({ name, rsc, items }) {
|
|
|
231
249
|
}
|
|
232
250
|
|
|
233
251
|
// Build via vite to satisfy production build requirement — per-item import verification already done via tsc
|
|
234
|
-
await writeFile(
|
|
252
|
+
await writeFile(
|
|
253
|
+
path.join(consumer, 'src/entry.tsx'),
|
|
254
|
+
`import * as React from 'react';\nexport const ok = true;\n`,
|
|
255
|
+
);
|
|
235
256
|
await run('pnpm', ['exec', 'vite', 'build'], { cwd: consumer });
|
|
236
257
|
console.log(`[${name}] vite build PASS for all ${items.length} items`);
|
|
237
258
|
|
|
@@ -307,7 +328,12 @@ try {
|
|
|
307
328
|
skipped: planned.length,
|
|
308
329
|
skippedIds: planned,
|
|
309
330
|
installable: available,
|
|
310
|
-
results: results.map((r) => ({
|
|
331
|
+
results: results.map((r) => ({
|
|
332
|
+
name: r.name,
|
|
333
|
+
verified: r.verified,
|
|
334
|
+
failed: r.failed,
|
|
335
|
+
failures: r.failures,
|
|
336
|
+
})),
|
|
311
337
|
};
|
|
312
338
|
await writeFile(
|
|
313
339
|
path.join(root, 'artifacts/registry-consumer-report.json'),
|
|
@@ -3,7 +3,9 @@ import { expect, test } from '@playwright/test';
|
|
|
3
3
|
import { CATALOG_URL } from '../../playwright.config';
|
|
4
4
|
|
|
5
5
|
test.describe('Catalog locale typography', () => {
|
|
6
|
-
test('Persian locale waits for IRANYekanX and renders Persian with correct font', async ({
|
|
6
|
+
test('Persian locale waits for IRANYekanX and renders Persian with correct font', async ({
|
|
7
|
+
page,
|
|
8
|
+
}) => {
|
|
7
9
|
await page.goto(`${CATALOG_URL}?locale=fa`);
|
|
8
10
|
// Wait for effectiveLocale to become fa (font ready) — html lang becomes fa only after font check passes
|
|
9
11
|
await expect(page.locator('html')).toHaveAttribute('lang', 'fa', { timeout: 10000 });
|
|
@@ -28,7 +30,8 @@ test.describe('Catalog locale typography', () => {
|
|
|
28
30
|
// Find an English technical value inside the Persian page (e.g., Bidi preview's TechnicalValue)
|
|
29
31
|
const englishInRtl = page.locator('text=a1b2c3d4').first();
|
|
30
32
|
// If not found, fallback to any LTR isolated element
|
|
31
|
-
const target =
|
|
33
|
+
const target =
|
|
34
|
+
(await englishInRtl.count()) > 0 ? englishInRtl : page.locator('[dir="ltr"]').first();
|
|
32
35
|
await expect(target).toBeVisible();
|
|
33
36
|
const fontFamily = await target.evaluate((el) => getComputedStyle(el).fontFamily);
|
|
34
37
|
// Should NOT be IRANYekanX, should be SF Pro or fallback
|
package/tsconfig.base.json
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
|
-
"lib": [
|
|
5
|
-
"ES2022",
|
|
6
|
-
"DOM",
|
|
7
|
-
"DOM.Iterable"
|
|
8
|
-
],
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
9
5
|
"module": "ESNext",
|
|
10
6
|
"moduleResolution": "Bundler",
|
|
11
7
|
"jsx": "react-jsx",
|
|
@@ -19,51 +15,21 @@
|
|
|
19
15
|
"declarationMap": true,
|
|
20
16
|
"sourceMap": true,
|
|
21
17
|
"paths": {
|
|
22
|
-
"@noe/design-tokens": [
|
|
23
|
-
|
|
24
|
-
],
|
|
25
|
-
"@noe/
|
|
26
|
-
|
|
27
|
-
],
|
|
28
|
-
"@noe/
|
|
29
|
-
|
|
30
|
-
],
|
|
31
|
-
"@noe/ui": [
|
|
32
|
-
|
|
33
|
-
],
|
|
34
|
-
"@noe/ui/*": [
|
|
35
|
-
|
|
36
|
-
]
|
|
37
|
-
"@noe/i18n": [
|
|
38
|
-
"./packages/i18n/src/index.ts"
|
|
39
|
-
],
|
|
40
|
-
"@noe/i18n/*": [
|
|
41
|
-
"./packages/i18n/src/*"
|
|
42
|
-
],
|
|
43
|
-
"@noe/data-ui": [
|
|
44
|
-
"./packages/data-ui/src/index.ts"
|
|
45
|
-
],
|
|
46
|
-
"@noe/data-ui/*": [
|
|
47
|
-
"./packages/data-ui/src/*"
|
|
48
|
-
],
|
|
49
|
-
"@noe/ai-ui": [
|
|
50
|
-
"./packages/ai-ui/src/index.ts"
|
|
51
|
-
],
|
|
52
|
-
"@noe/ai-ui/*": [
|
|
53
|
-
"./packages/ai-ui/src/*"
|
|
54
|
-
],
|
|
55
|
-
"@noe/workflow-ui": [
|
|
56
|
-
"./packages/workflow-ui/src/index.ts"
|
|
57
|
-
],
|
|
58
|
-
"@noe/workflow-ui/*": [
|
|
59
|
-
"./packages/workflow-ui/src/*"
|
|
60
|
-
],
|
|
61
|
-
"@noe/icons": [
|
|
62
|
-
"./packages/icons/src/index.tsx"
|
|
63
|
-
],
|
|
64
|
-
"@noe/icons/*": [
|
|
65
|
-
"./packages/icons/src/*"
|
|
66
|
-
]
|
|
18
|
+
"@noe/design-tokens": ["./packages/design-tokens/src/index.ts"],
|
|
19
|
+
"@noe/design-tokens/*": ["./packages/design-tokens/src/*"],
|
|
20
|
+
"@noe/design-tokens/palette": ["./packages/design-tokens/src/palette.ts"],
|
|
21
|
+
"@noe/ui": ["./packages/ui/src/index.ts"],
|
|
22
|
+
"@noe/ui/*": ["./packages/ui/src/*"],
|
|
23
|
+
"@noe/i18n": ["./packages/i18n/src/index.ts"],
|
|
24
|
+
"@noe/i18n/*": ["./packages/i18n/src/*"],
|
|
25
|
+
"@noe/data-ui": ["./packages/data-ui/src/index.ts"],
|
|
26
|
+
"@noe/data-ui/*": ["./packages/data-ui/src/*"],
|
|
27
|
+
"@noe/ai-ui": ["./packages/ai-ui/src/index.ts"],
|
|
28
|
+
"@noe/ai-ui/*": ["./packages/ai-ui/src/*"],
|
|
29
|
+
"@noe/workflow-ui": ["./packages/workflow-ui/src/index.ts"],
|
|
30
|
+
"@noe/workflow-ui/*": ["./packages/workflow-ui/src/*"],
|
|
31
|
+
"@noe/icons": ["./packages/icons/src/index.tsx"],
|
|
32
|
+
"@noe/icons/*": ["./packages/icons/src/*"]
|
|
67
33
|
}
|
|
68
34
|
}
|
|
69
|
-
}
|
|
35
|
+
}
|