tyrell-react 1.0.0-TC7

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/dist/components/TyButton.d.ts +50 -0
  4. package/dist/components/TyButton.d.ts.map +1 -0
  5. package/dist/components/TyButton.js +63 -0
  6. package/dist/components/TyButton.js.map +1 -0
  7. package/dist/components/TyCalendar.d.ts +63 -0
  8. package/dist/components/TyCalendar.d.ts.map +1 -0
  9. package/dist/components/TyCalendar.js +122 -0
  10. package/dist/components/TyCalendar.js.map +1 -0
  11. package/dist/components/TyCalendarMonth.d.ts +32 -0
  12. package/dist/components/TyCalendarMonth.d.ts.map +1 -0
  13. package/dist/components/TyCalendarMonth.js +54 -0
  14. package/dist/components/TyCalendarMonth.js.map +1 -0
  15. package/dist/components/TyCalendarNavigation.d.ts +21 -0
  16. package/dist/components/TyCalendarNavigation.d.ts.map +1 -0
  17. package/dist/components/TyCalendarNavigation.js +50 -0
  18. package/dist/components/TyCalendarNavigation.js.map +1 -0
  19. package/dist/components/TyCheckbox.d.ts +39 -0
  20. package/dist/components/TyCheckbox.d.ts.map +1 -0
  21. package/dist/components/TyCheckbox.js +68 -0
  22. package/dist/components/TyCheckbox.js.map +1 -0
  23. package/dist/components/TyCopy.d.ts +21 -0
  24. package/dist/components/TyCopy.d.ts.map +1 -0
  25. package/dist/components/TyCopy.js +42 -0
  26. package/dist/components/TyCopy.js.map +1 -0
  27. package/dist/components/TyDatePicker.d.ts +45 -0
  28. package/dist/components/TyDatePicker.d.ts.map +1 -0
  29. package/dist/components/TyDatePicker.js +114 -0
  30. package/dist/components/TyDatePicker.js.map +1 -0
  31. package/dist/components/TyDropdown.d.ts +51 -0
  32. package/dist/components/TyDropdown.d.ts.map +1 -0
  33. package/dist/components/TyDropdown.js +97 -0
  34. package/dist/components/TyDropdown.js.map +1 -0
  35. package/dist/components/TyIcon.d.ts +17 -0
  36. package/dist/components/TyIcon.d.ts.map +1 -0
  37. package/dist/components/TyIcon.js +41 -0
  38. package/dist/components/TyIcon.js.map +1 -0
  39. package/dist/components/TyInput.d.ts +65 -0
  40. package/dist/components/TyInput.d.ts.map +1 -0
  41. package/dist/components/TyInput.js +92 -0
  42. package/dist/components/TyInput.js.map +1 -0
  43. package/dist/components/TyModal.d.ts +29 -0
  44. package/dist/components/TyModal.d.ts.map +1 -0
  45. package/dist/components/TyModal.js +74 -0
  46. package/dist/components/TyModal.js.map +1 -0
  47. package/dist/components/TyMultiselect.d.ts +51 -0
  48. package/dist/components/TyMultiselect.d.ts.map +1 -0
  49. package/dist/components/TyMultiselect.js +92 -0
  50. package/dist/components/TyMultiselect.js.map +1 -0
  51. package/dist/components/TyOption.d.ts +10 -0
  52. package/dist/components/TyOption.d.ts.map +1 -0
  53. package/dist/components/TyOption.js +25 -0
  54. package/dist/components/TyOption.js.map +1 -0
  55. package/dist/components/TyPopup.d.ts +24 -0
  56. package/dist/components/TyPopup.d.ts.map +1 -0
  57. package/dist/components/TyPopup.js +61 -0
  58. package/dist/components/TyPopup.js.map +1 -0
  59. package/dist/components/TyResizeObserver.d.ts +11 -0
  60. package/dist/components/TyResizeObserver.d.ts.map +1 -0
  61. package/dist/components/TyResizeObserver.js +28 -0
  62. package/dist/components/TyResizeObserver.js.map +1 -0
  63. package/dist/components/TyScrollContainer.d.ts +25 -0
  64. package/dist/components/TyScrollContainer.d.ts.map +1 -0
  65. package/dist/components/TyScrollContainer.js +43 -0
  66. package/dist/components/TyScrollContainer.js.map +1 -0
  67. package/dist/components/TyStep.d.ts +17 -0
  68. package/dist/components/TyStep.d.ts.map +1 -0
  69. package/dist/components/TyStep.js +35 -0
  70. package/dist/components/TyStep.js.map +1 -0
  71. package/dist/components/TyTab.d.ts +13 -0
  72. package/dist/components/TyTab.d.ts.map +1 -0
  73. package/dist/components/TyTab.js +32 -0
  74. package/dist/components/TyTab.js.map +1 -0
  75. package/dist/components/TyTabs.d.ts +23 -0
  76. package/dist/components/TyTabs.d.ts.map +1 -0
  77. package/dist/components/TyTabs.js +48 -0
  78. package/dist/components/TyTabs.js.map +1 -0
  79. package/dist/components/TyTag.d.ts +22 -0
  80. package/dist/components/TyTag.d.ts.map +1 -0
  81. package/dist/components/TyTag.js +45 -0
  82. package/dist/components/TyTag.js.map +1 -0
  83. package/dist/components/TyTextarea.d.ts +37 -0
  84. package/dist/components/TyTextarea.d.ts.map +1 -0
  85. package/dist/components/TyTextarea.js +83 -0
  86. package/dist/components/TyTextarea.js.map +1 -0
  87. package/dist/components/TyTooltip.d.ts +17 -0
  88. package/dist/components/TyTooltip.d.ts.map +1 -0
  89. package/dist/components/TyTooltip.js +40 -0
  90. package/dist/components/TyTooltip.js.map +1 -0
  91. package/dist/components/TyWizard.d.ts +26 -0
  92. package/dist/components/TyWizard.d.ts.map +1 -0
  93. package/dist/components/TyWizard.js +50 -0
  94. package/dist/components/TyWizard.js.map +1 -0
  95. package/dist/components/index.d.ts +93 -0
  96. package/dist/components/index.d.ts.map +1 -0
  97. package/dist/components/index.js +106 -0
  98. package/dist/components/index.js.map +1 -0
  99. package/package.json +46 -0
  100. package/src/components/EventConventionTest.tsx +155 -0
  101. package/src/components/TyButton.tsx +140 -0
  102. package/src/components/TyCalendar.tsx +244 -0
  103. package/src/components/TyCalendarMonth.tsx +108 -0
  104. package/src/components/TyCalendarNavigation.tsx +91 -0
  105. package/src/components/TyCheckbox.tsx +138 -0
  106. package/src/components/TyCopy.tsx +78 -0
  107. package/src/components/TyDatePicker.tsx +216 -0
  108. package/src/components/TyDropdown.tsx +205 -0
  109. package/src/components/TyIcon.tsx +72 -0
  110. package/src/components/TyInput.tsx +194 -0
  111. package/src/components/TyModal.tsx +142 -0
  112. package/src/components/TyMultiselect.tsx +189 -0
  113. package/src/components/TyOption.tsx +42 -0
  114. package/src/components/TyPopup.tsx +111 -0
  115. package/src/components/TyResizeObserver.tsx +54 -0
  116. package/src/components/TyScrollContainer.tsx +87 -0
  117. package/src/components/TyStep.tsx +71 -0
  118. package/src/components/TyTab.tsx +63 -0
  119. package/src/components/TyTabs.tsx +93 -0
  120. package/src/components/TyTag.tsx +79 -0
  121. package/src/components/TyTextarea.tsx +144 -0
  122. package/src/components/TyTooltip.tsx +83 -0
  123. package/src/components/TyWizard.tsx +99 -0
  124. package/src/components/index.ts +230 -0
@@ -0,0 +1,189 @@
1
+ import React, { useEffect, useRef, useCallback } from 'react';
2
+
3
+ // Type definitions for Ty Multiselect component
4
+ export interface TyMultiselectEventDetail {
5
+ /** Array of currently selected values */
6
+ values: string[];
7
+ /** Action that triggered the change: "add" | "remove" */
8
+ action: 'add' | 'remove';
9
+ /** The specific item that was added or removed */
10
+ item: string;
11
+ }
12
+
13
+ export interface TyMultiselectProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange' | 'style'> {
14
+ style?: import('./TyInput').TyInputCSSProperties;
15
+ /** Current selected values as comma-separated string or array */
16
+ value?: string | string[];
17
+
18
+ /** Placeholder text when no items are selected */
19
+ placeholder?: string;
20
+
21
+ /** Disable the multiselect component */
22
+ disabled?: boolean;
23
+
24
+ /** Make the multiselect read-only */
25
+ readonly?: boolean;
26
+
27
+ /** Semantic styling variant */
28
+ flavor?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'neutral';
29
+
30
+ /** Label text for the multiselect */
31
+ label?: string;
32
+
33
+ /** Mark the field as required */
34
+ required?: boolean;
35
+
36
+ /**
37
+ * Switch to external (remote) search mode. Default is `false` — the
38
+ * multiselect filters its own children client-side. Set to `true` when you
39
+ * want to handle filtering yourself (e.g. server-side): the component will
40
+ * dispatch `search` events on each keystroke, and you must update the children
41
+ * in response. The `onSearch` prop receives those events.
42
+ */
43
+ externalSearch?: boolean;
44
+
45
+ /** Debounce in milliseconds (0-5000) */
46
+ debounce?: number;
47
+
48
+ /** Mobile section label for selected items */
49
+ selectedLabel?: string;
50
+
51
+ /** Form field name for form submission */
52
+ name?: string;
53
+
54
+ /** Callback when selection changes */
55
+ onChange?: (event: CustomEvent<TyMultiselectEventDetail>) => void;
56
+
57
+ /** Callback fired on each search input change (debounced by `debounce`). Use for external/server-side filtering. */
58
+ onSearch?: (event: CustomEvent<{ query: string; element: HTMLElement }>) => void;
59
+
60
+ /** Children should be TyTag components, not TyOption */
61
+ children?: React.ReactNode;
62
+ }
63
+
64
+ // React wrapper for ty-multiselect web component
65
+ export const TyMultiselect = React.forwardRef<HTMLElement, TyMultiselectProps>(
66
+ ({
67
+ value,
68
+ placeholder,
69
+ disabled,
70
+ readonly,
71
+ flavor,
72
+ label,
73
+ required,
74
+ externalSearch,
75
+ debounce,
76
+ selectedLabel,
77
+ name,
78
+ onChange,
79
+ onSearch,
80
+ children,
81
+ ...props
82
+ }, ref) => {
83
+ const elementRef = useRef<HTMLElement>(null);
84
+
85
+ // Handle ref forwarding
86
+ useEffect(() => {
87
+ if (ref && elementRef.current) {
88
+ if (typeof ref === 'function') {
89
+ ref(elementRef.current);
90
+ } else {
91
+ ref.current = elementRef.current;
92
+ }
93
+ }
94
+ }, [ref]);
95
+
96
+ // Handle change events
97
+ const handleChange = useCallback((event: Event) => {
98
+ const customEvent = event as CustomEvent<TyMultiselectEventDetail>;
99
+ if (onChange) {
100
+ onChange(customEvent);
101
+ }
102
+ }, [onChange]);
103
+
104
+ const handleSearch = useCallback((event: Event) => {
105
+ const customEvent = event as CustomEvent<{ query: string; element: HTMLElement }>;
106
+ if (onSearch) {
107
+ onSearch(customEvent);
108
+ }
109
+ }, [onSearch]);
110
+
111
+ // Set up event listeners
112
+ useEffect(() => {
113
+ const element = elementRef.current;
114
+ if (!element) return;
115
+
116
+ if (onChange) element.addEventListener('change', handleChange);
117
+ if (onSearch) element.addEventListener('search', handleSearch);
118
+
119
+ return () => {
120
+ if (onChange) element.removeEventListener('change', handleChange);
121
+ if (onSearch) element.removeEventListener('search', handleSearch);
122
+ };
123
+ }, [handleChange, handleSearch, onChange, onSearch]);
124
+
125
+ // Convert React props to web component attributes
126
+ const webComponentProps: Record<string, any> = {
127
+ ...props,
128
+ ref: elementRef,
129
+ };
130
+
131
+ // Handle value conversion (array to comma-separated string)
132
+ if (value !== undefined) {
133
+ const valueString = Array.isArray(value) ? value.join(',') : value;
134
+ webComponentProps.value = valueString;
135
+ }
136
+
137
+ // Add optional attributes only if they have values
138
+ if (placeholder) {
139
+ webComponentProps.placeholder = placeholder;
140
+ }
141
+
142
+ if (disabled) {
143
+ webComponentProps.disabled = ''; // Boolean attributes as empty string
144
+ }
145
+
146
+ if (readonly) {
147
+ webComponentProps.readonly = ''; // Boolean attributes as empty string
148
+ }
149
+
150
+ if (flavor) {
151
+ webComponentProps.flavor = flavor;
152
+ }
153
+
154
+ if (label) {
155
+ webComponentProps.label = label;
156
+ }
157
+
158
+ if (required) {
159
+ webComponentProps.required = ''; // Boolean attributes as empty string
160
+ }
161
+
162
+ if (name) {
163
+ webComponentProps.name = name;
164
+ }
165
+
166
+ // External (remote) search mode: parent owns filtering, multiselect dispatches search events
167
+ if (externalSearch) {
168
+ webComponentProps['external-search'] = '';
169
+ }
170
+
171
+ // Add debounce attribute
172
+ if (debounce !== undefined) {
173
+ webComponentProps.debounce = debounce;
174
+ }
175
+
176
+ // Add selectedLabel attribute
177
+ if (selectedLabel) {
178
+ webComponentProps['selected-label'] = selectedLabel;
179
+ }
180
+
181
+ return React.createElement(
182
+ 'ty-multiselect',
183
+ webComponentProps,
184
+ children
185
+ );
186
+ }
187
+ );
188
+
189
+ TyMultiselect.displayName = 'TyMultiselect';
@@ -0,0 +1,42 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ // Type definitions for Ty Option component
4
+ export interface TyOptionProps extends React.HTMLAttributes<HTMLElement> {
5
+ value?: string;
6
+ disabled?: boolean;
7
+ selected?: boolean;
8
+ hidden?: boolean;
9
+ children?: React.ReactNode;
10
+ }
11
+
12
+ // React wrapper for ty-option web component
13
+ export const TyOption = React.forwardRef<HTMLElement, TyOptionProps>(
14
+ ({ children, disabled, selected, hidden, ...props }, ref) => {
15
+ const elementRef = useRef<HTMLElement>(null);
16
+
17
+ // Handle ref forwarding
18
+ useEffect(() => {
19
+ if (ref && elementRef.current) {
20
+ if (typeof ref === 'function') {
21
+ ref(elementRef.current);
22
+ } else {
23
+ ref.current = elementRef.current;
24
+ }
25
+ }
26
+ }, [ref]);
27
+
28
+ return React.createElement(
29
+ 'ty-option',
30
+ {
31
+ ...props,
32
+ ...(disabled && { disabled: "" }),
33
+ ...(selected && { selected: "" }),
34
+ ...(hidden && { hidden: "" }),
35
+ ref: elementRef,
36
+ },
37
+ children
38
+ );
39
+ }
40
+ );
41
+
42
+ TyOption.displayName = 'TyOption';
@@ -0,0 +1,111 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ // Type definitions for Ty Popup component
4
+ export interface TyPopupProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onClose'> {
5
+ /** Preferred placement of the popup relative to anchor parent: "top" | "bottom" | "left" | "right" */
6
+ placement?: 'top' | 'bottom' | 'left' | 'right';
7
+
8
+ /** Distance offset from the anchor in pixels (default: 8) */
9
+ offset?: number;
10
+
11
+ /** Disable automatic click trigger - requires manual open/close via ref methods */
12
+ manual?: boolean;
13
+
14
+ /** Disable automatic close on outside click and ESC key */
15
+ disableClose?: boolean;
16
+
17
+ /** Fired when the popup opens (after the open animation starts) */
18
+ onOpen?: (event: CustomEvent) => void;
19
+
20
+ /** Fired when the popup closes */
21
+ onClose?: (event: CustomEvent) => void;
22
+
23
+ /** Popup content - popup should be a child of the anchor element */
24
+ children?: React.ReactNode;
25
+ }
26
+
27
+ // Programmatic API for popup control
28
+ export interface TyPopupElement extends HTMLElement {
29
+ openPopup(): void;
30
+ closePopup(): void;
31
+ togglePopup(): void;
32
+ }
33
+
34
+ // React wrapper for ty-popup web component
35
+ export const TyPopup = React.forwardRef<TyPopupElement, TyPopupProps>(
36
+ ({
37
+ placement,
38
+ offset,
39
+ manual,
40
+ disableClose,
41
+ onOpen,
42
+ onClose,
43
+ children,
44
+ ...props
45
+ }, ref) => {
46
+ const elementRef = useRef<TyPopupElement>(null);
47
+
48
+ // Handle ref forwarding
49
+ useEffect(() => {
50
+ if (ref && elementRef.current) {
51
+ if (typeof ref === 'function') {
52
+ ref(elementRef.current);
53
+ } else {
54
+ ref.current = elementRef.current;
55
+ }
56
+ }
57
+ }, [ref]);
58
+
59
+ // Listen for popup open/close events
60
+ useEffect(() => {
61
+ const element = elementRef.current;
62
+ if (!element) return;
63
+
64
+ const handleOpen = (event: Event) => {
65
+ if (onOpen) onOpen(event as CustomEvent);
66
+ };
67
+ const handleClose = (event: Event) => {
68
+ if (onClose) onClose(event as CustomEvent);
69
+ };
70
+
71
+ if (onOpen) element.addEventListener('open', handleOpen);
72
+ if (onClose) element.addEventListener('close', handleClose);
73
+
74
+ return () => {
75
+ if (onOpen) element.removeEventListener('open', handleOpen);
76
+ if (onClose) element.removeEventListener('close', handleClose);
77
+ };
78
+ }, [onOpen, onClose]);
79
+
80
+ // Convert React props to web component attributes
81
+ const webComponentProps: Record<string, any> = {
82
+ ...props,
83
+ ref: elementRef,
84
+ };
85
+
86
+ // Add optional attributes only if they have values
87
+ if (placement) {
88
+ webComponentProps.placement = placement;
89
+ }
90
+
91
+ if (offset !== undefined) {
92
+ webComponentProps.offset = offset.toString();
93
+ }
94
+
95
+ if (manual) {
96
+ webComponentProps.manual = ''; // Boolean attributes as empty string
97
+ }
98
+
99
+ if (disableClose) {
100
+ webComponentProps['disable-close'] = ''; // Boolean attributes as empty string
101
+ }
102
+
103
+ return React.createElement(
104
+ 'ty-popup',
105
+ webComponentProps,
106
+ children
107
+ );
108
+ }
109
+ );
110
+
111
+ TyPopup.displayName = 'TyPopup';
@@ -0,0 +1,54 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ // Type definitions for Ty ResizeObserver component
4
+ export interface TyResizeObserverProps extends React.HTMLAttributes<HTMLElement> {
5
+ /** Required unique identifier for size registry */
6
+ id: string;
7
+
8
+ /** Debounce in milliseconds (default: 0 = no debounce) */
9
+ debounce?: number;
10
+
11
+ /** Content to observe */
12
+ children?: React.ReactNode;
13
+ }
14
+
15
+ // React wrapper for ty-resize-observer web component
16
+ export const TyResizeObserver = React.forwardRef<HTMLElement, TyResizeObserverProps>(
17
+ ({
18
+ children,
19
+ id,
20
+ debounce,
21
+ ...props
22
+ }, ref) => {
23
+ const elementRef = useRef<HTMLElement>(null);
24
+
25
+ // Combine refs if needed
26
+ useEffect(() => {
27
+ if (ref && elementRef.current) {
28
+ if (typeof ref === 'function') {
29
+ ref(elementRef.current);
30
+ } else {
31
+ ref.current = elementRef.current;
32
+ }
33
+ }
34
+ }, [ref]);
35
+
36
+ // Convert React props to web component attributes
37
+ const webComponentProps: Record<string, any> = {
38
+ ...props,
39
+ ref: elementRef,
40
+ id,
41
+ };
42
+
43
+ // Add number attributes
44
+ if (debounce !== undefined) webComponentProps.debounce = debounce;
45
+
46
+ return React.createElement(
47
+ 'ty-resize-observer',
48
+ webComponentProps,
49
+ children
50
+ );
51
+ }
52
+ );
53
+
54
+ TyResizeObserver.displayName = 'TyResizeObserver';
@@ -0,0 +1,87 @@
1
+ import React, { useEffect, useRef, useImperativeHandle } from 'react';
2
+
3
+ // Type definitions for Ty ScrollContainer component
4
+ export interface TyScrollContainerProps extends React.HTMLAttributes<HTMLElement> {
5
+ /** Maximum height of the scroll container */
6
+ maxHeight?: string;
7
+
8
+ /** Enable/disable scroll shadows (default: true) */
9
+ shadow?: boolean;
10
+
11
+ /** Hide native scrollbar */
12
+ hideScrollbar?: boolean;
13
+
14
+ /** Content to scroll */
15
+ children?: React.ReactNode;
16
+ }
17
+
18
+ // Ref interface for imperative methods
19
+ export interface TyScrollContainerRef {
20
+ /** Force update shadows (useful after dynamic content changes) */
21
+ updateShadows: () => void;
22
+ /** Scroll to top */
23
+ scrollToTop: (smooth?: boolean) => void;
24
+ /** Scroll to bottom */
25
+ scrollToBottom: (smooth?: boolean) => void;
26
+ /** Get the underlying scroll element */
27
+ scrollElement: HTMLElement | null;
28
+ /** Get the native element */
29
+ element: HTMLElement | null;
30
+ }
31
+
32
+ // React wrapper for ty-scroll-container web component
33
+ export const TyScrollContainer = React.forwardRef<TyScrollContainerRef, TyScrollContainerProps>(
34
+ ({
35
+ children,
36
+ maxHeight,
37
+ shadow,
38
+ hideScrollbar,
39
+ ...props
40
+ }, ref) => {
41
+ const elementRef = useRef<HTMLElement>(null);
42
+
43
+ // Expose imperative methods via ref
44
+ useImperativeHandle(ref, () => ({
45
+ updateShadows: () => {
46
+ const el = elementRef.current as any;
47
+ el?.updateShadows?.();
48
+ },
49
+ scrollToTop: (smooth = true) => {
50
+ const el = elementRef.current as any;
51
+ el?.scrollToTop?.(smooth);
52
+ },
53
+ scrollToBottom: (smooth = true) => {
54
+ const el = elementRef.current as any;
55
+ el?.scrollToBottom?.(smooth);
56
+ },
57
+ get scrollElement() {
58
+ const el = elementRef.current as any;
59
+ return el?.scrollElement ?? null;
60
+ },
61
+ get element() {
62
+ return elementRef.current;
63
+ }
64
+ }), []);
65
+
66
+ // Convert React props to web component attributes
67
+ const webComponentProps: Record<string, any> = {
68
+ ...props,
69
+ ref: elementRef,
70
+ };
71
+
72
+ // Add string attributes
73
+ if (maxHeight) webComponentProps['max-height'] = maxHeight;
74
+
75
+ // Add boolean attributes
76
+ if (shadow === false) webComponentProps.shadow = 'false';
77
+ if (hideScrollbar) webComponentProps['hide-scrollbar'] = true;
78
+
79
+ return React.createElement(
80
+ 'ty-scroll-container',
81
+ webComponentProps,
82
+ children
83
+ );
84
+ }
85
+ );
86
+
87
+ TyScrollContainer.displayName = 'TyScrollContainer';
@@ -0,0 +1,71 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ // Type definitions for Ty Step component
4
+ export interface TyStepProps extends React.HTMLAttributes<HTMLElement> {
5
+ /** Required unique identifier for the step */
6
+ id: string;
7
+
8
+ /** Main step title displayed in indicator */
9
+ label?: string;
10
+
11
+ /** Optional subtitle/description */
12
+ description?: string;
13
+
14
+ /** Whether the step is disabled */
15
+ disabled?: boolean;
16
+
17
+ /** User-controlled status override */
18
+ status?: 'completed' | 'active' | 'pending' | 'error';
19
+
20
+ /** Step content */
21
+ children?: React.ReactNode;
22
+ }
23
+
24
+ // React wrapper for ty-step web component
25
+ export const TyStep = React.forwardRef<HTMLElement, TyStepProps>(
26
+ ({
27
+ children,
28
+ id,
29
+ label,
30
+ description,
31
+ disabled,
32
+ status,
33
+ ...props
34
+ }, ref) => {
35
+ const elementRef = useRef<HTMLElement>(null);
36
+
37
+ // Combine refs if needed
38
+ useEffect(() => {
39
+ if (ref && elementRef.current) {
40
+ if (typeof ref === 'function') {
41
+ ref(elementRef.current);
42
+ } else {
43
+ ref.current = elementRef.current;
44
+ }
45
+ }
46
+ }, [ref]);
47
+
48
+ // Convert React props to web component attributes
49
+ const webComponentProps: Record<string, any> = {
50
+ ...props,
51
+ ref: elementRef,
52
+ id,
53
+ };
54
+
55
+ // Add string attributes
56
+ if (label) webComponentProps.label = label;
57
+ if (description) webComponentProps.description = description;
58
+ if (status) webComponentProps.status = status;
59
+
60
+ // Add boolean attributes
61
+ if (disabled) webComponentProps.disabled = true;
62
+
63
+ return React.createElement(
64
+ 'ty-step',
65
+ webComponentProps,
66
+ children
67
+ );
68
+ }
69
+ );
70
+
71
+ TyStep.displayName = 'TyStep';
@@ -0,0 +1,63 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ // Type definitions for Ty Tab component
4
+ export interface TyTabProps extends React.HTMLAttributes<HTMLElement> {
5
+ /** Required unique identifier */
6
+ id: string;
7
+
8
+ /** Simple text label */
9
+ label?: string;
10
+
11
+ /** Whether the tab is disabled */
12
+ disabled?: boolean;
13
+
14
+ /** Tab content */
15
+ children?: React.ReactNode;
16
+ }
17
+
18
+ // React wrapper for ty-tab web component
19
+ export const TyTab = React.forwardRef<HTMLElement, TyTabProps>(
20
+ ({
21
+ children,
22
+ id,
23
+ label,
24
+ disabled,
25
+ ...props
26
+ }, ref) => {
27
+ const elementRef = useRef<HTMLElement>(null);
28
+
29
+ // Combine refs if needed
30
+ useEffect(() => {
31
+ if (ref && elementRef.current) {
32
+ if (typeof ref === 'function') {
33
+ ref(elementRef.current);
34
+ } else {
35
+ ref.current = elementRef.current;
36
+ }
37
+ }
38
+ }, [ref]);
39
+
40
+ // Convert React props to web component attributes
41
+ const webComponentProps: Record<string, any> = {
42
+ ...props,
43
+ ref: elementRef,
44
+ };
45
+
46
+ // Add required attribute
47
+ webComponentProps.id = id;
48
+
49
+ // Add boolean attributes
50
+ if (disabled) webComponentProps.disabled = '';
51
+
52
+ // Add string attributes
53
+ if (label) webComponentProps.label = label;
54
+
55
+ return React.createElement(
56
+ 'ty-tab',
57
+ webComponentProps,
58
+ children
59
+ );
60
+ }
61
+ );
62
+
63
+ TyTab.displayName = 'TyTab';