@designcrowd/fe-shared-lib 1.5.20-ast-icons-1 → 1.5.20-dts-upgrades-2

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 (34) hide show
  1. package/.claude/settings.local.json +34 -0
  2. package/.npm-publish-token +1 -0
  3. package/MODERNIZATION_ROADMAP.md +264 -0
  4. package/docs/plans/2026-01-19-typescript-declarations-design.md +114 -0
  5. package/docs/plans/2026-01-19-typescript-declarations-tdd-plan.md +953 -0
  6. package/index.d.ts +309 -0
  7. package/package.json +2 -1
  8. package/src/atoms/components/Icon/Icon.stories.js +0 -2
  9. package/src/atoms/components/Icon/Icon.vue +0 -4
  10. package/src/useSharedLibTranslate.js +2 -0
  11. package/types-test/all-components.test.ts +81 -0
  12. package/types-test/basic-imports.test.ts +16 -0
  13. package/types-test/button-props.test.ts +63 -0
  14. package/types-test/checkbox-toggle-props.test.ts +78 -0
  15. package/types-test/dropdown-props.test.ts +36 -0
  16. package/types-test/icon-props.test.ts +42 -0
  17. package/types-test/loader-props.test.ts +7 -0
  18. package/types-test/modal-props.test.ts +39 -0
  19. package/types-test/select-props.test.ts +97 -0
  20. package/types-test/text-input-props.test.ts +80 -0
  21. package/types-test/textarea-props.test.ts +72 -0
  22. package/types-test/tsconfig.json +12 -0
  23. package/dist/css/tailwind-brandCrowd.css +0 -2496
  24. package/dist/css/tailwind-brandPage.css +0 -2180
  25. package/dist/css/tailwind-crazyDomains.css +0 -2496
  26. package/dist/css/tailwind-designCom.css +0 -2496
  27. package/dist/css/tailwind-designCrowd.css +0 -2496
  28. package/public/css/tailwind-brandCrowd.css +0 -2504
  29. package/public/css/tailwind-brandPage.css +0 -2184
  30. package/public/css/tailwind-crazyDomains.css +0 -2504
  31. package/public/css/tailwind-designCom.css +0 -2504
  32. package/public/css/tailwind-designCrowd.css +0 -2504
  33. package/src/atoms/components/Icon/icons/digital-business-card-filled.vue +0 -8
  34. package/src/atoms/components/Icon/icons/link-in-bio-filled.vue +0 -8
@@ -0,0 +1,953 @@
1
+ # TypeScript Declarations TDD Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Add TypeScript declaration files to `@designcrowd/fe-shared-lib` so consumers get type checking and IDE autocomplete without converting the library to TypeScript.
6
+
7
+ **Architecture:** Create a single `index.d.ts` file at package root that declares all exports from `index.js`. Use detailed prop interfaces for the 10 most-used components and generic `DefineComponent<{}, {}, any>` stubs for the rest. Update `package.json` exports to include the types field.
8
+
9
+ **Tech Stack:** TypeScript declarations, Vue 3 `DefineComponent` type from `vue`
10
+
11
+ ---
12
+
13
+ ## TDD Approach for Type Declarations
14
+
15
+ For TypeScript declarations, "tests" are **compilation tests** - TypeScript files that:
16
+ - Import from the package
17
+ - Use the types in ways that should succeed (positive tests)
18
+ - Optionally test that invalid usage fails to compile (negative tests)
19
+
20
+ **RED** = Test file fails to compile (because types don't exist yet)
21
+ **GREEN** = Test file compiles successfully (types are correct)
22
+
23
+ ---
24
+
25
+ ## Task 1: Set Up Type Test Infrastructure
26
+
27
+ **Files:**
28
+ - Create: `types-test/tsconfig.json`
29
+ - Create: `types-test/basic-imports.test.ts`
30
+
31
+ **Step 1: Create tsconfig for type tests**
32
+
33
+ ```json
34
+ {
35
+ "compilerOptions": {
36
+ "target": "ES2020",
37
+ "module": "ESNext",
38
+ "moduleResolution": "bundler",
39
+ "strict": true,
40
+ "noEmit": true,
41
+ "skipLibCheck": true,
42
+ "types": ["node"]
43
+ },
44
+ "include": ["*.test.ts"],
45
+ "references": [{ "path": ".." }]
46
+ }
47
+ ```
48
+
49
+ **Step 2: Write failing test for basic imports**
50
+
51
+ ```typescript
52
+ // types-test/basic-imports.test.ts
53
+ // This file tests that basic imports work - compilation = pass
54
+
55
+ import { Button, Modal, Icon, setSharedLibLocaleAsync, tr } from '..';
56
+
57
+ // If this file compiles, the basic exports are typed
58
+ const _button: typeof Button = Button;
59
+ const _modal: typeof Modal = Modal;
60
+ const _icon: typeof Icon = Icon;
61
+
62
+ // Test utility function types
63
+ async function testUtils() {
64
+ await setSharedLibLocaleAsync('en-US');
65
+ const translated: string = tr('key');
66
+ const translatedWithParams: string = tr('key', { name: 'test' });
67
+ }
68
+ ```
69
+
70
+ **Step 3: Run test to verify it fails (RED)**
71
+
72
+ ```bash
73
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
74
+ ```
75
+
76
+ Expected: FAIL with `TS7016: Could not find a declaration file for module`
77
+
78
+ **Step 4: Commit test infrastructure**
79
+
80
+ ```bash
81
+ git add types-test/
82
+ git commit -m "$(cat <<'EOF'
83
+ test: add type test infrastructure for TDD
84
+
85
+ Sets up TypeScript compilation tests to verify declaration files work correctly.
86
+
87
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
88
+ EOF
89
+ )"
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Task 2: Create Minimal index.d.ts Skeleton
95
+
96
+ **Files:**
97
+ - Create: `index.d.ts`
98
+
99
+ **Step 1: The test from Task 1 is already failing (RED)**
100
+
101
+ Verify it still fails:
102
+ ```bash
103
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
104
+ ```
105
+
106
+ **Step 2: Write minimal declaration file to make test pass (GREEN)**
107
+
108
+ ```typescript
109
+ // index.d.ts
110
+ import { DefineComponent } from 'vue';
111
+
112
+ // ============ Utility Functions ============
113
+ export function setSharedLibLocaleAsync(locale?: string): Promise<void>;
114
+ export function tr(key: string, params?: Record<string, unknown>): string;
115
+
116
+ // ============ API Clients ============
117
+ export const brandPageApiClient: unknown;
118
+ export const brandCrowdApiClient: unknown;
119
+
120
+ // ============ Constants ============
121
+ export const WEBSITE_UPGRADE_CONTEXT_TYPES: Record<string, string>;
122
+
123
+ // ============ Components (Stubs) ============
124
+ // These will be refined in subsequent tasks
125
+
126
+ export const Button: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
127
+ export const Modal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
128
+ export const Icon: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
129
+
130
+ // ... all other components as stubs (added in Task 3)
131
+ ```
132
+
133
+ **Step 3: Run test to verify it passes (GREEN)**
134
+
135
+ ```bash
136
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
137
+ ```
138
+
139
+ Expected: PASS (no output, exit code 0)
140
+
141
+ **Step 4: Commit**
142
+
143
+ ```bash
144
+ git add index.d.ts
145
+ git commit -m "$(cat <<'EOF'
146
+ feat: add minimal TypeScript declaration skeleton
147
+
148
+ Initial index.d.ts with utility functions and component stubs.
149
+
150
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
151
+ EOF
152
+ )"
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Task 3: Add All Component Stub Declarations
158
+
159
+ **Files:**
160
+ - Modify: `index.d.ts`
161
+ - Create: `types-test/all-components.test.ts`
162
+
163
+ **Step 1: Write failing test for all component imports (RED)**
164
+
165
+ ```typescript
166
+ // types-test/all-components.test.ts
167
+ import {
168
+ // Experiences
169
+ UploadYourLogoDropzone,
170
+ UploadYourLogoApplication,
171
+ UploadedLogoSearchResultCard,
172
+ SignUpModal,
173
+ SignUp,
174
+ SignIn,
175
+ ForgotPasswordModal,
176
+ ForgotPassword,
177
+ ResetPasswordModal,
178
+ ResetPassword,
179
+ ResetPasswordSuccessModal,
180
+ PaymentConfigList,
181
+ PaymentConfigDropdown,
182
+ SellDomainNameListModal,
183
+ SellDomainNameList,
184
+ SellDomainNameWidget,
185
+ PublishBrandPageModal,
186
+ PublishBrandPageCard,
187
+ WebsiteContextualUpgradeModal,
188
+ // Atoms
189
+ Button,
190
+ ButtonGroup,
191
+ Dropdown,
192
+ DropdownItem,
193
+ Icon,
194
+ DcomIcon,
195
+ Modal,
196
+ Loader,
197
+ Tooltip,
198
+ Picture,
199
+ HelloBar,
200
+ PromoCard,
201
+ SearchBar,
202
+ StarRating,
203
+ TabMenu,
204
+ TextInput,
205
+ TextCopyField,
206
+ Textarea,
207
+ Toggle,
208
+ Checkbox,
209
+ ColorPicker,
210
+ Carousel,
211
+ Checktile,
212
+ Pill,
213
+ PillBar,
214
+ Notice,
215
+ Masonry,
216
+ CollapsiblePanel,
217
+ Slider,
218
+ Price,
219
+ HashRouteModal,
220
+ Select,
221
+ NumberStepper,
222
+ CopyToClipboardText,
223
+ SparkleIcon,
224
+ // Utilities
225
+ setSharedLibLocaleAsync,
226
+ tr,
227
+ brandPageApiClient,
228
+ brandCrowdApiClient,
229
+ WEBSITE_UPGRADE_CONTEXT_TYPES,
230
+ } from '..';
231
+
232
+ // All imports should be defined
233
+ const components = [
234
+ UploadYourLogoDropzone,
235
+ UploadYourLogoApplication,
236
+ UploadedLogoSearchResultCard,
237
+ SignUpModal,
238
+ SignUp,
239
+ SignIn,
240
+ ForgotPasswordModal,
241
+ ForgotPassword,
242
+ ResetPasswordModal,
243
+ ResetPassword,
244
+ ResetPasswordSuccessModal,
245
+ PaymentConfigList,
246
+ PaymentConfigDropdown,
247
+ SellDomainNameListModal,
248
+ SellDomainNameList,
249
+ SellDomainNameWidget,
250
+ PublishBrandPageModal,
251
+ PublishBrandPageCard,
252
+ WebsiteContextualUpgradeModal,
253
+ Button,
254
+ ButtonGroup,
255
+ Dropdown,
256
+ DropdownItem,
257
+ Icon,
258
+ DcomIcon,
259
+ Modal,
260
+ Loader,
261
+ Tooltip,
262
+ Picture,
263
+ HelloBar,
264
+ PromoCard,
265
+ SearchBar,
266
+ StarRating,
267
+ TabMenu,
268
+ TextInput,
269
+ TextCopyField,
270
+ Textarea,
271
+ Toggle,
272
+ Checkbox,
273
+ ColorPicker,
274
+ Carousel,
275
+ Checktile,
276
+ Pill,
277
+ PillBar,
278
+ Notice,
279
+ Masonry,
280
+ CollapsiblePanel,
281
+ Slider,
282
+ Price,
283
+ HashRouteModal,
284
+ Select,
285
+ NumberStepper,
286
+ CopyToClipboardText,
287
+ SparkleIcon,
288
+ ];
289
+ ```
290
+
291
+ **Step 2: Run test to verify it fails (RED)**
292
+
293
+ ```bash
294
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
295
+ ```
296
+
297
+ Expected: FAIL with errors for missing exports
298
+
299
+ **Step 3: Add all component stubs to index.d.ts (GREEN)**
300
+
301
+ Add to `index.d.ts`:
302
+
303
+ ```typescript
304
+ // ============ Experience Components (Stubs) ============
305
+ export const UploadYourLogoDropzone: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
306
+ export const UploadYourLogoApplication: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
307
+ export const UploadedLogoSearchResultCard: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
308
+ export const SignUpModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
309
+ export const SignUp: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
310
+ export const SignIn: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
311
+ export const ForgotPasswordModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
312
+ export const ForgotPassword: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
313
+ export const ResetPasswordModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
314
+ export const ResetPassword: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
315
+ export const ResetPasswordSuccessModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
316
+ export const PaymentConfigList: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
317
+ export const PaymentConfigDropdown: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
318
+ export const SellDomainNameListModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
319
+ export const SellDomainNameList: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
320
+ export const SellDomainNameWidget: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
321
+ export const PublishBrandPageModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
322
+ export const PublishBrandPageCard: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
323
+ export const WebsiteContextualUpgradeModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
324
+
325
+ // ============ Atom Components (Stubs) ============
326
+ export const ButtonGroup: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
327
+ export const Dropdown: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
328
+ export const DropdownItem: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
329
+ export const DcomIcon: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
330
+ export const Loader: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
331
+ export const Tooltip: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
332
+ export const Picture: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
333
+ export const HelloBar: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
334
+ export const PromoCard: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
335
+ export const SearchBar: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
336
+ export const StarRating: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
337
+ export const TabMenu: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
338
+ export const TextCopyField: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
339
+ export const ColorPicker: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
340
+ export const Carousel: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
341
+ export const Checktile: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
342
+ export const Pill: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
343
+ export const PillBar: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
344
+ export const Notice: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
345
+ export const Masonry: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
346
+ export const CollapsiblePanel: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
347
+ export const Slider: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
348
+ export const Price: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
349
+ export const HashRouteModal: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
350
+ export const NumberStepper: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
351
+ export const CopyToClipboardText: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
352
+ export const SparkleIcon: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
353
+
354
+ // Detailed components (will be typed in subsequent tasks)
355
+ export const TextInput: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
356
+ export const Textarea: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
357
+ export const Toggle: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
358
+ export const Checkbox: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
359
+ export const Select: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
360
+ ```
361
+
362
+ **Step 4: Run test to verify it passes (GREEN)**
363
+
364
+ ```bash
365
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
366
+ ```
367
+
368
+ Expected: PASS
369
+
370
+ **Step 5: Commit**
371
+
372
+ ```bash
373
+ git add index.d.ts types-test/all-components.test.ts
374
+ git commit -m "$(cat <<'EOF'
375
+ feat: add stub declarations for all components
376
+
377
+ All 55 exported components now have TypeScript declarations (as generic stubs).
378
+
379
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
380
+ EOF
381
+ )"
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Task 4: Add Detailed Button Props Interface
387
+
388
+ **Files:**
389
+ - Modify: `index.d.ts`
390
+ - Create: `types-test/button-props.test.ts`
391
+
392
+ **Step 1: Write failing test for Button props (RED)**
393
+
394
+ ```typescript
395
+ // types-test/button-props.test.ts
396
+ import { Button } from '..';
397
+ import type { ComponentProps } from 'vue';
398
+
399
+ // Test that Button accepts specific props
400
+ // This will fail until we add detailed ButtonProps
401
+
402
+ type ButtonProps = ComponentProps<typeof Button>;
403
+
404
+ // These should all be valid
405
+ const validProps: ButtonProps = {
406
+ label: 'Click me',
407
+ variant: 'primary',
408
+ size: 'medium',
409
+ disabled: false,
410
+ isBusy: true,
411
+ fullWidth: false,
412
+ icon: 'chevron-right',
413
+ url: 'https://example.com',
414
+ theme: 'brandCrowd',
415
+ };
416
+
417
+ // Test specific prop types
418
+ const label: ButtonProps['label'] = 'test';
419
+ const variant: ButtonProps['variant'] = 'primary';
420
+ const disabled: ButtonProps['disabled'] = true;
421
+ ```
422
+
423
+ **Step 2: Run test to verify it fails (RED)**
424
+
425
+ ```bash
426
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
427
+ ```
428
+
429
+ Expected: FAIL - props are typed as `unknown` so specific assignments fail
430
+
431
+ **Step 3: Add detailed ButtonProps interface (GREEN)**
432
+
433
+ Update `index.d.ts` - replace the Button stub with:
434
+
435
+ ```typescript
436
+ // ============ Detailed Component Types ============
437
+
438
+ export interface ButtonProps {
439
+ attrs?: Record<string, unknown>;
440
+ label?: string;
441
+ url?: string;
442
+ theme?: 'brandCrowd' | 'crazyDomains' | string;
443
+ variant?: 'primary' | 'secondary' | 'success' | 'outline' | 'outline-primary' | 'outline-success' | 'outline-no-hover' | 'warning' | 'info' | 'info-filled' | 'gray' | 'no-border' | 'flat' | 'pill' | 'dark-mode-pill' | 'ai' | 'primary-with-icon' | string;
444
+ size?: 'small' | 'small-wide' | 'small-medium' | 'medium' | 'large' | string | null;
445
+ iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | string;
446
+ icon?: string;
447
+ iconViewBox?: string;
448
+ iconLeft?: string;
449
+ iconLeftSize?: string;
450
+ iconRight?: string;
451
+ iconRightSize?: string;
452
+ iconTop?: string;
453
+ iconTopSize?: string;
454
+ iconColor?: string;
455
+ fullWidth?: boolean;
456
+ fullHeight?: boolean;
457
+ classes?: string | Record<string, boolean>;
458
+ containerClasses?: string;
459
+ greyOutLeft?: boolean;
460
+ white?: boolean;
461
+ rounded?: boolean;
462
+ roundedLeft?: boolean;
463
+ roundedRight?: boolean;
464
+ disabled?: boolean;
465
+ isBusy?: boolean;
466
+ isBusyLabel?: string;
467
+ download?: string;
468
+ active?: boolean;
469
+ target?: '_self' | '_blank' | '_parent' | '_top' | string;
470
+ justify?: 'center' | 'between' | string;
471
+ type?: 'button' | 'submit' | 'reset' | string;
472
+ showLabel?: boolean;
473
+ dataAttribute?: string;
474
+ altText?: string;
475
+ }
476
+
477
+ export interface ButtonEmits {
478
+ 'on-click': [event: Event];
479
+ }
480
+
481
+ export const Button: DefineComponent<ButtonProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, ButtonEmits>;
482
+ ```
483
+
484
+ **Step 4: Run test to verify it passes (GREEN)**
485
+
486
+ ```bash
487
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
488
+ ```
489
+
490
+ Expected: PASS
491
+
492
+ **Step 5: Commit**
493
+
494
+ ```bash
495
+ git add index.d.ts types-test/button-props.test.ts
496
+ git commit -m "$(cat <<'EOF'
497
+ feat: add detailed ButtonProps interface
498
+
499
+ Button component now has full prop type definitions with IDE autocomplete.
500
+
501
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
502
+ EOF
503
+ )"
504
+ ```
505
+
506
+ ---
507
+
508
+ ## Task 5: Add Detailed Modal Props Interface
509
+
510
+ **Files:**
511
+ - Modify: `index.d.ts`
512
+ - Create: `types-test/modal-props.test.ts`
513
+
514
+ **Step 1: Write failing test for Modal props (RED)**
515
+
516
+ ```typescript
517
+ // types-test/modal-props.test.ts
518
+ import { Modal } from '..';
519
+ import type { ComponentProps } from 'vue';
520
+
521
+ type ModalProps = ComponentProps<typeof Modal>;
522
+
523
+ const validProps: ModalProps = {
524
+ visible: true,
525
+ mandatory: false,
526
+ size: 'md',
527
+ closeOnEsc: true,
528
+ };
529
+
530
+ const visible: ModalProps['visible'] = true;
531
+ const size: ModalProps['size'] = 'xl';
532
+ ```
533
+
534
+ **Step 2: Run test to verify RED, then add ModalProps (GREEN)**
535
+
536
+ ```typescript
537
+ export interface ModalProps {
538
+ simple?: boolean;
539
+ removeHorizontalMargin?: boolean;
540
+ removeHorizontalPadding?: boolean;
541
+ visible?: boolean;
542
+ mandatory?: boolean;
543
+ mode?: 'image' | string;
544
+ classes?: string | Record<string, boolean>;
545
+ contentClasses?: string[];
546
+ size?: 'md' | 'xl' | string;
547
+ fullScreenBreakpoint?: 'sm' | string;
548
+ closeOnEsc?: boolean;
549
+ hideScrollbar?: boolean;
550
+ showModalBackgroundImage?: boolean;
551
+ disableBodyScrollOnVisible?: boolean;
552
+ darkOverlay?: boolean;
553
+ transparentModal?: boolean;
554
+ }
555
+
556
+ export interface ModalEmits {
557
+ 'close-modal': [event?: Event];
558
+ }
559
+
560
+ export const Modal: DefineComponent<ModalProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, ModalEmits>;
561
+ ```
562
+
563
+ **Step 3: Run test, verify pass, commit**
564
+
565
+ ```bash
566
+ git add index.d.ts types-test/modal-props.test.ts
567
+ git commit -m "$(cat <<'EOF'
568
+ feat: add detailed ModalProps interface
569
+
570
+ Modal component now has full prop type definitions.
571
+
572
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
573
+ EOF
574
+ )"
575
+ ```
576
+
577
+ ---
578
+
579
+ ## Task 6: Add Detailed Icon Props Interface
580
+
581
+ **Files:**
582
+ - Modify: `index.d.ts`
583
+ - Create: `types-test/icon-props.test.ts`
584
+
585
+ **Step 1: Write failing test, then implement (RED → GREEN)**
586
+
587
+ ```typescript
588
+ // types-test/icon-props.test.ts
589
+ import { Icon } from '..';
590
+ import type { ComponentProps } from 'vue';
591
+
592
+ type IconProps = ComponentProps<typeof Icon>;
593
+
594
+ const validProps: IconProps = {
595
+ name: 'chevron-right',
596
+ size: 'md',
597
+ color: 'primary-500',
598
+ };
599
+ ```
600
+
601
+ **Step 2: Add IconProps interface**
602
+
603
+ ```typescript
604
+ export interface IconProps {
605
+ viewBox?: string;
606
+ name: string;
607
+ altText?: string | null;
608
+ color?: string;
609
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full' | 'button-icon' | string;
610
+ classes?: string;
611
+ }
612
+
613
+ export const Icon: DefineComponent<IconProps>;
614
+ ```
615
+
616
+ **Step 3: Commit**
617
+
618
+ ---
619
+
620
+ ## Task 7: Add Detailed TextInput Props Interface
621
+
622
+ **Files:**
623
+ - Modify: `index.d.ts`
624
+ - Create: `types-test/text-input-props.test.ts`
625
+
626
+ **Step 1: Write test then implement**
627
+
628
+ ```typescript
629
+ export interface TextInputProps {
630
+ // From FormControlMixin
631
+ attrs?: Record<string, unknown>;
632
+ modelValue?: string | number;
633
+ id?: string;
634
+ placeholder?: string;
635
+ size?: 'sm' | string;
636
+ label?: string;
637
+ showLabelScreenReaderOnly?: boolean;
638
+ icon?: string;
639
+ required?: boolean;
640
+ error?: boolean;
641
+ warning?: boolean;
642
+ success?: boolean;
643
+ disabled?: boolean;
644
+ readonly?: boolean;
645
+ name?: string;
646
+ maxlength?: number;
647
+ minlength?: number;
648
+ isSpaceDisabled?: boolean;
649
+ requiredMessage?: string;
650
+ // TextInput-specific
651
+ type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | string;
652
+ enableClear?: boolean;
653
+ enableClearConfirmation?: boolean;
654
+ borderLeft?: boolean;
655
+ borderRight?: boolean;
656
+ prefixText?: string;
657
+ elementClasses?: string;
658
+ }
659
+
660
+ export interface TextInputEmits {
661
+ 'update:modelValue': [value: string | number];
662
+ 'input': [value: string | number];
663
+ 'keyup': [value: string | number];
664
+ 'keydown': [value: string | number];
665
+ 'focus': [value: string | number];
666
+ 'blur': [value: string | number];
667
+ 'enter-key-up': [value: string | number];
668
+ 'on-clear': [];
669
+ 'on-clear-confirmation': [];
670
+ }
671
+
672
+ export const TextInput: DefineComponent<TextInputProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, TextInputEmits>;
673
+ ```
674
+
675
+ ---
676
+
677
+ ## Task 8: Add Detailed Textarea Props Interface
678
+
679
+ **Step 1: Add TextareaProps (extends FormControlMixin props + textarea-specific)**
680
+
681
+ ```typescript
682
+ export interface TextareaProps {
683
+ // From FormControlMixin (same as TextInput)
684
+ attrs?: Record<string, unknown>;
685
+ modelValue?: string | number;
686
+ id?: string;
687
+ placeholder?: string;
688
+ size?: 'sm' | 'md' | 'lg' | string;
689
+ label?: string;
690
+ showLabelScreenReaderOnly?: boolean;
691
+ icon?: string;
692
+ required?: boolean;
693
+ error?: boolean;
694
+ warning?: boolean;
695
+ success?: boolean;
696
+ disabled?: boolean;
697
+ readonly?: boolean;
698
+ name?: string;
699
+ maxlength?: number;
700
+ minlength?: number;
701
+ isSpaceDisabled?: boolean;
702
+ requiredMessage?: string;
703
+ // Textarea-specific
704
+ resize?: boolean;
705
+ shouldAutoFitContent?: boolean;
706
+ elementClasses?: string;
707
+ }
708
+
709
+ export const Textarea: DefineComponent<TextareaProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, TextInputEmits>;
710
+ ```
711
+
712
+ ---
713
+
714
+ ## Task 9: Add Detailed Checkbox and Toggle Props Interfaces
715
+
716
+ ```typescript
717
+ export interface CheckboxProps {
718
+ modelValue: boolean;
719
+ id: string;
720
+ label?: string;
721
+ showLabelScreenReaderOnly?: boolean;
722
+ inline?: boolean;
723
+ required?: boolean;
724
+ disabled?: boolean;
725
+ color?: 'success' | 'info' | 'error' | 'warning' | 'primary' | string;
726
+ size?: 'sm' | 'md' | string;
727
+ showBorder?: boolean;
728
+ classes?: string | Record<string, boolean>;
729
+ }
730
+
731
+ export interface CheckboxEmits {
732
+ 'update:modelValue': [value: boolean];
733
+ }
734
+
735
+ export const Checkbox: DefineComponent<CheckboxProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, CheckboxEmits>;
736
+
737
+ // Toggle uses same props as Checkbox
738
+ export const Toggle: DefineComponent<CheckboxProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, CheckboxEmits>;
739
+ ```
740
+
741
+ ---
742
+
743
+ ## Task 10: Add Detailed Dropdown Props Interface
744
+
745
+ ```typescript
746
+ export interface DropdownProps {
747
+ menuAlign?: 'left' | 'right' | string;
748
+ title?: string;
749
+ elementClasses?: string;
750
+ menuElementClasses?: string;
751
+ disabled?: boolean;
752
+ show?: boolean;
753
+ iconSize?: 'xs' | 'sm' | 'md' | 'lg' | string;
754
+ tooltip?: string;
755
+ }
756
+
757
+ export interface DropdownEmits {
758
+ 'update:show': [value: boolean];
759
+ }
760
+
761
+ export const Dropdown: DefineComponent<DropdownProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, DropdownEmits>;
762
+ ```
763
+
764
+ ---
765
+
766
+ ## Task 11: Add Detailed Select Props Interface
767
+
768
+ ```typescript
769
+ export interface SelectOption {
770
+ $isDisabled?: boolean;
771
+ isCustom?: boolean;
772
+ label?: string;
773
+ [key: string]: unknown;
774
+ }
775
+
776
+ export interface SelectProps {
777
+ // From selectMixin
778
+ isInternalSearch?: boolean;
779
+ options: SelectOption[] | string[];
780
+ modelValue?: string | SelectOption | null;
781
+ trackBy?: string | null;
782
+ label?: string;
783
+ imageUrlField?: string | null;
784
+ isSearchable?: boolean;
785
+ shouldHideSelected?: boolean;
786
+ placeholder?: string;
787
+ shouldAllowEmpty?: boolean;
788
+ shouldResetAfter?: boolean;
789
+ shouldCloseOnSelect?: boolean;
790
+ customLabel?: (option: SelectOption | string, label?: string) => string;
791
+ shouldAllowCustom?: boolean;
792
+ customPlaceholder?: string;
793
+ customPosition?: 'top' | 'bottom' | string;
794
+ id?: string | null;
795
+ optionsLimit?: number;
796
+ shouldPreserveSearch?: boolean;
797
+ shouldPreselectFirst?: boolean;
798
+ shouldPreventAutofocus?: boolean;
799
+ isDisabled?: boolean;
800
+ // From Select.vue
801
+ name?: string;
802
+ selectLabel?: string;
803
+ selectedLabel?: string;
804
+ deselectLabel?: string;
805
+ shouldShowLabels?: boolean;
806
+ maxHeight?: number;
807
+ isLoading?: boolean;
808
+ openDirection?: 'above' | 'below' | 'top' | 'bottom' | string;
809
+ shouldShowNoResults?: boolean;
810
+ tabindex?: number;
811
+ shouldSelectExactMatchOnBlur?: boolean;
812
+ isInvalid?: boolean;
813
+ }
814
+
815
+ export interface SelectEmits {
816
+ 'update:modelValue': [option: SelectOption | string | null, id?: string | null];
817
+ 'search-change': [search: string, id?: string | null];
818
+ 'remove': [option: SelectOption | string, id?: string | null];
819
+ 'open': [id?: string | null];
820
+ 'close': [value: SelectOption | string | null, id?: string | null];
821
+ 'custom': [label: string, id?: string | null];
822
+ }
823
+
824
+ export const Select: DefineComponent<SelectProps, Record<string, unknown>, unknown, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, SelectEmits>;
825
+ ```
826
+
827
+ ---
828
+
829
+ ## Task 12: Add Loader Props Interface
830
+
831
+ ```typescript
832
+ // Loader has no props - it's a simple SVG spinner
833
+ export interface LoaderProps {}
834
+
835
+ export const Loader: DefineComponent<LoaderProps>;
836
+ ```
837
+
838
+ ---
839
+
840
+ ## Task 13: Update package.json Exports
841
+
842
+ **Files:**
843
+ - Modify: `package.json`
844
+
845
+ **Step 1: Write failing test that verifies types field is recognized**
846
+
847
+ The test infrastructure already validates this - if the types field is missing, the imports would fail.
848
+
849
+ **Step 2: Update package.json exports**
850
+
851
+ Add `"types"` field to the exports:
852
+
853
+ ```json
854
+ {
855
+ "exports": {
856
+ ".": {
857
+ "types": "./index.d.ts",
858
+ "require": "./index.cjs",
859
+ "import": "./index.js"
860
+ },
861
+ "./src/*.vue": {
862
+ "import": "./src/*.vue"
863
+ },
864
+ "./src/*.js": {
865
+ "import": "./src/*.js"
866
+ }
867
+ }
868
+ }
869
+ ```
870
+
871
+ **Step 3: Run all type tests to verify (GREEN)**
872
+
873
+ ```bash
874
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
875
+ ```
876
+
877
+ **Step 4: Commit**
878
+
879
+ ```bash
880
+ git add package.json
881
+ git commit -m "$(cat <<'EOF'
882
+ feat: add types field to package.json exports
883
+
884
+ Consumers will now automatically get TypeScript declarations.
885
+
886
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
887
+ EOF
888
+ )"
889
+ ```
890
+
891
+ ---
892
+
893
+ ## Task 14: Final Verification and Cleanup
894
+
895
+ **Step 1: Run full type check**
896
+
897
+ ```bash
898
+ cd /home/zknowles/repos/fe-shared-lib && npx tsc -p types-test/tsconfig.json --noEmit
899
+ ```
900
+
901
+ **Step 2: Verify lint passes**
902
+
903
+ ```bash
904
+ npm run lint
905
+ ```
906
+
907
+ **Step 3: Final commit combining all declaration files**
908
+
909
+ ```bash
910
+ git add -A
911
+ git commit -m "$(cat <<'EOF'
912
+ feat: complete TypeScript declarations for fe-shared-lib
913
+
914
+ - Full prop interfaces for 10 most-used components (Button, Modal, Icon,
915
+ TextInput, Textarea, Checkbox, Toggle, Dropdown, Select, Loader)
916
+ - Generic stubs for remaining 45+ components
917
+ - Type-safe utility functions (setSharedLibLocaleAsync, tr)
918
+ - Comprehensive type tests validating all exports
919
+
920
+ Resolves TS7016 errors in consuming projects like BrandCrowd.Nuxt.
921
+
922
+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
923
+ EOF
924
+ )"
925
+ ```
926
+
927
+ ---
928
+
929
+ ## Verification Checklist
930
+
931
+ Before marking complete:
932
+
933
+ - [ ] `index.d.ts` exists at package root
934
+ - [ ] All 55 exports from `index.js` have declarations
935
+ - [ ] 10 most-used components have detailed prop interfaces
936
+ - [ ] `package.json` has `"types": "./index.d.ts"` in exports
937
+ - [ ] All type tests pass: `npx tsc -p types-test/tsconfig.json --noEmit`
938
+ - [ ] Lint passes: `npm run lint`
939
+ - [ ] Each task had a failing test before implementation
940
+
941
+ ---
942
+
943
+ ## Post-Implementation: Consumer Testing
944
+
945
+ After publishing, verify in BrandCrowd.Nuxt:
946
+
947
+ ```bash
948
+ # In BrandCrowd.Nuxt directory
949
+ npm link ../fe-shared-lib
950
+ npx vue-tsc --noEmit
951
+ ```
952
+
953
+ Expected: TS7016 errors for `@designcrowd/fe-shared-lib` should be resolved.