tyrell-react 1.0.0-RC10 → 1.0.0-RC12

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 (65) hide show
  1. package/dist/components/TyCalendar.d.ts +6 -0
  2. package/dist/components/TyCalendar.d.ts.map +1 -1
  3. package/dist/components/TyCalendar.js +16 -2
  4. package/dist/components/TyCalendar.js.map +1 -1
  5. package/dist/components/TyCalendarMonth.d.ts +4 -0
  6. package/dist/components/TyCalendarMonth.d.ts.map +1 -1
  7. package/dist/components/TyCalendarMonth.js +5 -1
  8. package/dist/components/TyCalendarMonth.js.map +1 -1
  9. package/dist/components/TyCalendarNavigation.d.ts +4 -0
  10. package/dist/components/TyCalendarNavigation.d.ts.map +1 -1
  11. package/dist/components/TyCalendarNavigation.js +5 -1
  12. package/dist/components/TyCalendarNavigation.js.map +1 -1
  13. package/dist/components/TyCheckbox.d.ts +2 -0
  14. package/dist/components/TyCheckbox.d.ts.map +1 -1
  15. package/dist/components/TyCheckbox.js +4 -1
  16. package/dist/components/TyCheckbox.js.map +1 -1
  17. package/dist/components/TyCopy.d.ts +4 -0
  18. package/dist/components/TyCopy.d.ts.map +1 -1
  19. package/dist/components/TyCopy.js +19 -1
  20. package/dist/components/TyCopy.js.map +1 -1
  21. package/dist/components/TyDatePicker.d.ts +4 -0
  22. package/dist/components/TyDatePicker.d.ts.map +1 -1
  23. package/dist/components/TyDatePicker.js +7 -1
  24. package/dist/components/TyDatePicker.js.map +1 -1
  25. package/dist/components/TyOption.d.ts +8 -0
  26. package/dist/components/TyOption.d.ts.map +1 -1
  27. package/dist/components/TyOption.js +3 -1
  28. package/dist/components/TyOption.js.map +1 -1
  29. package/dist/components/TyScrollContainer.d.ts +26 -1
  30. package/dist/components/TyScrollContainer.d.ts.map +1 -1
  31. package/dist/components/TyScrollContainer.js +41 -24
  32. package/dist/components/TyScrollContainer.js.map +1 -1
  33. package/dist/components/TySelect.d.ts +75 -0
  34. package/dist/components/TySelect.d.ts.map +1 -0
  35. package/dist/components/TySelect.js +134 -0
  36. package/dist/components/TySelect.js.map +1 -0
  37. package/dist/components/index.d.ts +6 -8
  38. package/dist/components/index.d.ts.map +1 -1
  39. package/dist/components/index.js +5 -4
  40. package/dist/components/index.js.map +1 -1
  41. package/dist/version.d.ts +1 -1
  42. package/dist/version.js +1 -1
  43. package/package.json +1 -1
  44. package/src/components/TyCalendar.tsx +30 -1
  45. package/src/components/TyCalendarMonth.tsx +11 -1
  46. package/src/components/TyCalendarNavigation.tsx +11 -1
  47. package/src/components/TyCheckbox.tsx +8 -2
  48. package/src/components/TyCopy.tsx +25 -1
  49. package/src/components/TyDatePicker.tsx +16 -0
  50. package/src/components/TyOption.tsx +14 -1
  51. package/src/components/TyScrollContainer.tsx +74 -24
  52. package/src/components/TySelect.tsx +240 -0
  53. package/src/components/index.ts +8 -13
  54. package/src/version.ts +1 -1
  55. package/dist/components/TyDropdown.d.ts +0 -62
  56. package/dist/components/TyDropdown.d.ts.map +0 -1
  57. package/dist/components/TyDropdown.js +0 -124
  58. package/dist/components/TyDropdown.js.map +0 -1
  59. package/dist/components/TyMultiselect.d.ts +0 -57
  60. package/dist/components/TyMultiselect.d.ts.map +0 -1
  61. package/dist/components/TyMultiselect.js +0 -111
  62. package/dist/components/TyMultiselect.js.map +0 -1
  63. package/src/components/EventConventionTest.tsx +0 -155
  64. package/src/components/TyDropdown.tsx +0 -240
  65. package/src/components/TyMultiselect.tsx +0 -208
@@ -26,6 +26,12 @@ export interface TyCopyProps extends Omit<React.HTMLAttributes<HTMLElement>, 'on
26
26
 
27
27
  /** Required field */
28
28
  required?: boolean;
29
+
30
+ /** Fired after the value is copied to the clipboard */
31
+ onCopySuccess?: (event: CustomEvent) => void;
32
+
33
+ /** Fired when copying to the clipboard fails */
34
+ onCopyError?: (event: CustomEvent) => void;
29
35
  }
30
36
 
31
37
  // React wrapper for ty-copy web component
@@ -39,7 +45,9 @@ export const TyCopy = React.forwardRef<HTMLElement, TyCopyProps>(
39
45
  multiline,
40
46
  disabled,
41
47
  required,
42
- ...props
48
+ onCopySuccess,
49
+ onCopyError,
50
+ ...props
43
51
  }, ref) => {
44
52
  const elementRef = useRef<HTMLElement>(null);
45
53
 
@@ -54,6 +62,22 @@ export const TyCopy = React.forwardRef<HTMLElement, TyCopyProps>(
54
62
  }
55
63
  }, [ref]);
56
64
 
65
+ // Custom events → React callbacks
66
+ useEffect(() => {
67
+ const el = elementRef.current;
68
+ if (!el) return;
69
+ const bound: Array<[string, EventListener]> = [];
70
+ if (onCopySuccess) {
71
+ const h = (e: Event) => onCopySuccess(e as CustomEvent);
72
+ el.addEventListener('copy-success', h); bound.push(['copy-success', h]);
73
+ }
74
+ if (onCopyError) {
75
+ const h = (e: Event) => onCopyError(e as CustomEvent);
76
+ el.addEventListener('copy-error', h); bound.push(['copy-error', h]);
77
+ }
78
+ return () => bound.forEach(([n, h]) => el.removeEventListener(n, h));
79
+ }, [onCopySuccess, onCopyError]);
80
+
57
81
  const isMultiline = useBooleanProperty(elementRef, 'multiline', multiline);
58
82
  const isDisabled = useBooleanProperty(elementRef, 'disabled', disabled);
59
83
  const isRequired = useBooleanProperty(elementRef, 'required', required);
@@ -50,6 +50,12 @@ export interface TyDatePickerProps extends Omit<React.HTMLAttributes<HTMLElement
50
50
 
51
51
  /** Whether to include time selection */
52
52
  withTime?: boolean;
53
+
54
+ /** Earliest selectable date (ISO "YYYY-MM-DD") */
55
+ min?: string;
56
+
57
+ /** Latest selectable date (ISO "YYYY-MM-DD") */
58
+ max?: string;
53
59
 
54
60
  /** Callback when the date value changes */
55
61
  onChange?: (event: CustomEvent<TyDatePickerEventDetail>) => void;
@@ -76,6 +82,8 @@ export const TyDatePicker = React.forwardRef<HTMLElement, TyDatePickerProps>(
76
82
  format,
77
83
  locale,
78
84
  withTime,
85
+ min,
86
+ max,
79
87
  onChange,
80
88
  onOpen,
81
89
  onClose,
@@ -208,6 +216,14 @@ export const TyDatePicker = React.forwardRef<HTMLElement, TyDatePickerProps>(
208
216
  webComponentProps['with-time'] = ''; // Convert camelCase to kebab-case
209
217
  }
210
218
 
219
+ if (min) {
220
+ webComponentProps.min = min;
221
+ }
222
+
223
+ if (max) {
224
+ webComponentProps.max = max;
225
+ }
226
+
211
227
  return React.createElement('ty-date-picker', webComponentProps);
212
228
  }
213
229
  );
@@ -4,6 +4,17 @@ import { useBooleanProperty } from '../utils/use-boolean-prop';
4
4
  // Type definitions for Ty Option component
5
5
  export interface TyOptionProps extends React.HTMLAttributes<HTMLElement> {
6
6
  value?: string;
7
+
8
+ /**
9
+ * Clean display text (native <option label> semantics) — used by ty-select
10
+ * for field summaries and by ty-selected-tags chips when the option's
11
+ * children are rich HTML. data-* attributes feed chip templates.
12
+ */
13
+ label?: string;
14
+
15
+ /** Semantic flavor — carried onto ty-selected-tags chips */
16
+ flavor?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'neutral' | 'info';
17
+
7
18
  disabled?: boolean;
8
19
  selected?: boolean;
9
20
  hidden?: boolean;
@@ -12,7 +23,7 @@ export interface TyOptionProps extends React.HTMLAttributes<HTMLElement> {
12
23
 
13
24
  // React wrapper for ty-option web component
14
25
  export const TyOption = React.forwardRef<HTMLElement, TyOptionProps>(
15
- ({ children, disabled, selected, hidden, ...props }, ref) => {
26
+ ({ children, label, flavor, disabled, selected, hidden, ...props }, ref) => {
16
27
  const elementRef = useRef<HTMLElement>(null);
17
28
 
18
29
  // Handle ref forwarding
@@ -34,6 +45,8 @@ export const TyOption = React.forwardRef<HTMLElement, TyOptionProps>(
34
45
  'ty-option',
35
46
  {
36
47
  ...props,
48
+ ...(label && { label }),
49
+ ...(flavor && { flavor }),
37
50
  ...(isDisabled && { disabled: "" }),
38
51
  ...(isSelected && { selected: "" }),
39
52
  ...(isHidden && { hidden: "" }),
@@ -2,6 +2,14 @@ import React, { useEffect, useRef, useImperativeHandle } from 'react';
2
2
  import { needsPropertyBridge } from '../utils/react-version';
3
3
  import { useBooleanProperty, coerceBool } from '../utils/use-boolean-prop';
4
4
 
5
+ /** Detail payload for nearstart / nearend events. */
6
+ export interface TyScrollNearEdgeDetail {
7
+ distance: number;
8
+ scrollTop: number;
9
+ scrollHeight: number;
10
+ clientHeight: number;
11
+ }
12
+
5
13
  // Type definitions for Ty ScrollContainer component
6
14
  export interface TyScrollContainerProps extends React.HTMLAttributes<HTMLElement> {
7
15
  /** Maximum height of the scroll container */
@@ -10,9 +18,27 @@ export interface TyScrollContainerProps extends React.HTMLAttributes<HTMLElement
10
18
  /** Enable/disable scroll shadows (default: true) */
11
19
  shadow?: boolean;
12
20
 
13
- /** Hide native scrollbar */
21
+ /** Hide native scrollbar (no custom scrollbar) */
14
22
  hideScrollbar?: boolean;
15
23
 
24
+ /** Use the styled custom scrollbar */
25
+ customScrollbar?: boolean;
26
+
27
+ /** Enable horizontal scrolling */
28
+ overflowX?: boolean;
29
+
30
+ /** Preserve visual position when content is prepended above the viewport */
31
+ scrollAnchoring?: boolean;
32
+
33
+ /** Distance (px) from an edge at which nearstart/nearend fire (default 100) */
34
+ nearEdgeThreshold?: number;
35
+
36
+ /** Fired once when scrolled within the threshold of the bottom */
37
+ onNearEnd?: (event: CustomEvent<TyScrollNearEdgeDetail>) => void;
38
+
39
+ /** Fired once when scrolled within the threshold of the top */
40
+ onNearStart?: (event: CustomEvent<TyScrollNearEdgeDetail>) => void;
41
+
16
42
  /** Content to scroll */
17
43
  children?: React.ReactNode;
18
44
  }
@@ -25,6 +51,12 @@ export interface TyScrollContainerRef {
25
51
  scrollToTop: (smooth?: boolean) => void;
26
52
  /** Scroll to bottom */
27
53
  scrollToBottom: (smooth?: boolean) => void;
54
+ /** Scroll to far left */
55
+ scrollToLeft: (smooth?: boolean) => void;
56
+ /** Scroll to far right */
57
+ scrollToRight: (smooth?: boolean) => void;
58
+ /** Scroll a descendant (element or CSS selector) into view */
59
+ scrollToElement: (target: Element | string, smooth?: boolean) => void;
28
60
  /** Get the underlying scroll element */
29
61
  scrollElement: HTMLElement | null;
30
62
  /** Get the native element */
@@ -38,35 +70,29 @@ export const TyScrollContainer = React.forwardRef<TyScrollContainerRef, TyScroll
38
70
  maxHeight,
39
71
  shadow,
40
72
  hideScrollbar,
73
+ customScrollbar,
74
+ overflowX,
75
+ scrollAnchoring,
76
+ nearEdgeThreshold,
77
+ onNearEnd,
78
+ onNearStart,
41
79
  ...props
42
80
  }, ref) => {
43
81
  const elementRef = useRef<HTMLElement>(null);
44
82
 
45
83
  // Expose imperative methods via ref
46
84
  useImperativeHandle(ref, () => ({
47
- updateShadows: () => {
48
- const el = elementRef.current as any;
49
- el?.updateShadows?.();
50
- },
51
- scrollToTop: (smooth = true) => {
52
- const el = elementRef.current as any;
53
- el?.scrollToTop?.(smooth);
54
- },
55
- scrollToBottom: (smooth = true) => {
56
- const el = elementRef.current as any;
57
- el?.scrollToBottom?.(smooth);
58
- },
59
- get scrollElement() {
60
- const el = elementRef.current as any;
61
- return el?.scrollElement ?? null;
62
- },
63
- get element() {
64
- return elementRef.current;
65
- }
85
+ updateShadows: () => { (elementRef.current as any)?.updateShadows?.(); },
86
+ scrollToTop: (smooth = true) => { (elementRef.current as any)?.scrollToTop?.(smooth); },
87
+ scrollToBottom: (smooth = true) => { (elementRef.current as any)?.scrollToBottom?.(smooth); },
88
+ scrollToLeft: (smooth = true) => { (elementRef.current as any)?.scrollToLeft?.(smooth); },
89
+ scrollToRight: (smooth = true) => { (elementRef.current as any)?.scrollToRight?.(smooth); },
90
+ scrollToElement: (target, smooth = true) => { (elementRef.current as any)?.scrollToElement?.(target, smooth); },
91
+ get scrollElement() { return (elementRef.current as any)?.scrollElement ?? null; },
92
+ get element() { return elementRef.current; }
66
93
  }), []);
67
94
 
68
- // shadow defaults to true; only the explicit-false case matters at the
69
- // attribute level. Bridge it imperatively so flipping back to true
95
+ // shadow defaults to true; bridge it imperatively so flipping back to true
70
96
  // propagates on React 18.
71
97
  useEffect(() => {
72
98
  if (!needsPropertyBridge) return;
@@ -76,7 +102,27 @@ export const TyScrollContainer = React.forwardRef<TyScrollContainerRef, TyScroll
76
102
  const next = coerceBool(shadow);
77
103
  if (Boolean(el.shadow) !== next) el.shadow = next;
78
104
  }, [shadow]);
105
+
79
106
  const isHideScrollbar = useBooleanProperty(elementRef, 'hideScrollbar', hideScrollbar);
107
+ const isCustomScrollbar = useBooleanProperty(elementRef, 'customScrollbar', customScrollbar);
108
+ const isOverflowX = useBooleanProperty(elementRef, 'overflowX', overflowX);
109
+ const isScrollAnchoring = useBooleanProperty(elementRef, 'scrollAnchoring', scrollAnchoring);
110
+
111
+ // Custom events → React callbacks
112
+ useEffect(() => {
113
+ const el = elementRef.current;
114
+ if (!el) return;
115
+ const bound: Array<[string, EventListener]> = [];
116
+ if (onNearEnd) {
117
+ const h = (e: Event) => onNearEnd(e as CustomEvent<TyScrollNearEdgeDetail>);
118
+ el.addEventListener('nearend', h); bound.push(['nearend', h]);
119
+ }
120
+ if (onNearStart) {
121
+ const h = (e: Event) => onNearStart(e as CustomEvent<TyScrollNearEdgeDetail>);
122
+ el.addEventListener('nearstart', h); bound.push(['nearstart', h]);
123
+ }
124
+ return () => bound.forEach(([n, h]) => el.removeEventListener(n, h));
125
+ }, [onNearEnd, onNearStart]);
80
126
 
81
127
  // Convert React props to web component attributes
82
128
  const webComponentProps: Record<string, any> = {
@@ -84,12 +130,16 @@ export const TyScrollContainer = React.forwardRef<TyScrollContainerRef, TyScroll
84
130
  ref: elementRef,
85
131
  };
86
132
 
87
- // Add string attributes
133
+ // String attributes
88
134
  if (maxHeight) webComponentProps['max-height'] = maxHeight;
135
+ if (nearEdgeThreshold != null) webComponentProps['near-edge-threshold'] = String(nearEdgeThreshold);
89
136
 
90
- // Add boolean attributes
137
+ // Boolean attributes
91
138
  if (shadow !== undefined && !coerceBool(shadow)) webComponentProps.shadow = 'false';
92
139
  if (isHideScrollbar) webComponentProps['hide-scrollbar'] = '';
140
+ if (isCustomScrollbar) webComponentProps['custom-scrollbar'] = '';
141
+ if (isOverflowX) webComponentProps['overflow-x'] = '';
142
+ if (isScrollAnchoring) webComponentProps['scroll-anchoring'] = '';
93
143
 
94
144
  return React.createElement(
95
145
  'ty-scroll-container',
@@ -0,0 +1,240 @@
1
+ import React, { useEffect, useRef, useCallback } from 'react';
2
+ import { needsPropertyBridge } from '../utils/react-version';
3
+ import { useBooleanProperty } from '../utils/use-boolean-prop';
4
+
5
+ // Type definitions for Ty Select component
6
+ export interface TySelectItem {
7
+ value: string;
8
+ label: string;
9
+ flavor: string | null;
10
+ }
11
+
12
+ export interface TySelectEventDetail {
13
+ /** Scalar for single select, array when `multiple` */
14
+ value: string | string[] | null;
15
+ /** Always the array form of the selection */
16
+ values: string[];
17
+ /** Rich info per selected value — enough to render chips out-of-band */
18
+ items: TySelectItem[];
19
+ /** Action that triggered the change */
20
+ action: 'add' | 'remove' | 'clear' | 'set';
21
+ /** The specific value that changed */
22
+ item: string | null;
23
+ }
24
+
25
+ export interface TySelectProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange' | 'style'> {
26
+ style?: import('./TyInput').TyInputCSSProperties;
27
+
28
+ /** Selected value(s) — string, comma-separated string, or array */
29
+ value?: string | string[];
30
+
31
+ /** Multi select (native <select multiple> semantics). Default: single. */
32
+ multiple?: boolean;
33
+
34
+ /** Compact content-hugging trigger (toolbars, filter bars) instead of the full-width field look */
35
+ compact?: boolean;
36
+
37
+ /** Placeholder shown while nothing is selected */
38
+ placeholder?: string;
39
+
40
+ /** Label text above the field */
41
+ label?: string;
42
+
43
+ /** Form field name — single submits one entry, multiple submits repeated entries */
44
+ name?: string;
45
+
46
+ /** Disable the select */
47
+ disabled?: boolean;
48
+
49
+ /** Read-only */
50
+ readonly?: boolean;
51
+
52
+ /** Mark the field as required */
53
+ required?: boolean;
54
+
55
+ /**
56
+ * Search row visibility: 'auto' (default) shows it only for 8+ options,
57
+ * 'always' / 'never' force it. external-search always shows it.
58
+ */
59
+ searchable?: 'auto' | 'always' | 'never' | boolean;
60
+
61
+ /**
62
+ * External (remote) search mode — the component stops filtering and emits
63
+ * debounced `search` events; replace the option children in response.
64
+ */
65
+ externalSearch?: boolean;
66
+
67
+ /** Debounce for the search event in ms (0-5000) */
68
+ debounce?: number;
69
+
70
+ /** Loading state — shows a spinner in the options area (external search in flight) */
71
+ loading?: boolean;
72
+
73
+ /** Size variant */
74
+ size?: 'sm' | 'md' | 'lg';
75
+
76
+ /** Callback when selection changes */
77
+ onChange?: (event: CustomEvent<TySelectEventDetail>) => void;
78
+
79
+ /** Callback fired on each search input change (debounced). Use for external/server-side filtering. */
80
+ onSearch?: (event: CustomEvent<{ query: string; element: HTMLElement }>) => void;
81
+ onOpen?: (event: CustomEvent) => void;
82
+ onClose?: (event: CustomEvent) => void;
83
+
84
+ /** TyOption children (plus optional slot="trigger" / slot="start" / slot="end" elements) */
85
+ children?: React.ReactNode;
86
+ }
87
+
88
+ // React wrapper for ty-select web component
89
+ export const TySelect = React.forwardRef<HTMLElement, TySelectProps>(
90
+ ({
91
+ value,
92
+ multiple,
93
+ compact,
94
+ placeholder,
95
+ label,
96
+ name,
97
+ disabled,
98
+ readonly,
99
+ required,
100
+ searchable,
101
+ externalSearch,
102
+ debounce,
103
+ loading,
104
+ size,
105
+ onChange,
106
+ onSearch,
107
+ onOpen,
108
+ onClose,
109
+ children,
110
+ ...props
111
+ }, ref) => {
112
+ const elementRef = useRef<HTMLElement>(null);
113
+
114
+ // Handle ref forwarding
115
+ useEffect(() => {
116
+ if (ref && elementRef.current) {
117
+ if (typeof ref === 'function') {
118
+ ref(elementRef.current);
119
+ } else {
120
+ ref.current = elementRef.current;
121
+ }
122
+ }
123
+ }, [ref]);
124
+
125
+ // Imperatively sync `value` so resets ('' or null) reliably clear the
126
+ // visible selection. React 18 workaround; React 19+ handles this natively.
127
+ useEffect(() => {
128
+ if (!needsPropertyBridge) return;
129
+ const element = elementRef.current as any;
130
+ if (!element) return;
131
+ const next = Array.isArray(value) ? value.join(',') : (value ?? '');
132
+ if (element.value !== next) {
133
+ element.value = next;
134
+ }
135
+ }, [value]);
136
+
137
+ // Handle events
138
+ const handleChange = useCallback((event: Event) => {
139
+ if (onChange) onChange(event as CustomEvent<TySelectEventDetail>);
140
+ }, [onChange]);
141
+
142
+ const handleSearch = useCallback((event: Event) => {
143
+ if (onSearch) onSearch(event as CustomEvent<{ query: string; element: HTMLElement }>);
144
+ }, [onSearch]);
145
+
146
+ const handleOpen = useCallback((event: Event) => { if (onOpen) onOpen(event as CustomEvent); }, [onOpen]);
147
+ const handleClose = useCallback((event: Event) => { if (onClose) onClose(event as CustomEvent); }, [onClose]);
148
+
149
+ // Set up event listeners
150
+ useEffect(() => {
151
+ const element = elementRef.current;
152
+ if (!element) return;
153
+
154
+ if (onChange) element.addEventListener('change', handleChange);
155
+ if (onSearch) element.addEventListener('search', handleSearch);
156
+ if (onOpen) element.addEventListener('open', handleOpen);
157
+ if (onClose) element.addEventListener('close', handleClose);
158
+
159
+ return () => {
160
+ if (onChange) element.removeEventListener('change', handleChange);
161
+ if (onSearch) element.removeEventListener('search', handleSearch);
162
+ if (onOpen) element.removeEventListener('open', handleOpen);
163
+ if (onClose) element.removeEventListener('close', handleClose);
164
+ };
165
+ }, [handleChange, handleSearch, handleOpen, handleClose, onChange, onSearch, onOpen, onClose]);
166
+
167
+ // Imperative property sync for boolean props (see use-boolean-prop.ts).
168
+ const isMultiple = useBooleanProperty(elementRef, 'multiple', multiple);
169
+ const isCompact = useBooleanProperty(elementRef, 'compact', compact);
170
+ const isDisabled = useBooleanProperty(elementRef, 'disabled', disabled);
171
+ const isReadonly = useBooleanProperty(elementRef, 'readonly', readonly);
172
+ const isRequired = useBooleanProperty(elementRef, 'required', required);
173
+ const isLoading = useBooleanProperty(elementRef, 'loading', loading);
174
+ const isExternalSearch = useBooleanProperty(elementRef, 'externalSearch', externalSearch);
175
+
176
+ // Convert React props to web component attributes
177
+ const webComponentProps: Record<string, any> = {
178
+ ...props,
179
+ ref: elementRef,
180
+ };
181
+
182
+ // Handle value conversion (array to comma-separated string)
183
+ if (value !== undefined) {
184
+ webComponentProps.value = Array.isArray(value) ? value.join(',') : value;
185
+ }
186
+
187
+ if (isMultiple) webComponentProps.multiple = '';
188
+ if (isCompact) webComponentProps.compact = '';
189
+ if (isDisabled) webComponentProps.disabled = '';
190
+ if (isReadonly) webComponentProps.readonly = '';
191
+ if (isRequired) webComponentProps.required = '';
192
+ if (isLoading) webComponentProps.loading = '';
193
+ if (isExternalSearch) webComponentProps['external-search'] = '';
194
+
195
+ if (placeholder) webComponentProps.placeholder = placeholder;
196
+ if (label) webComponentProps.label = label;
197
+ if (name) webComponentProps.name = name;
198
+ if (size) webComponentProps.size = size;
199
+ if (debounce !== undefined) webComponentProps.debounce = debounce.toString();
200
+ if (searchable === 'always' || searchable === true) webComponentProps.searchable = 'true';
201
+ else if (searchable === 'never' || searchable === false) webComponentProps.searchable = 'false';
202
+ // 'auto' / undefined → omit (component default)
203
+
204
+ return React.createElement('ty-select', webComponentProps, children);
205
+ }
206
+ );
207
+
208
+ TySelect.displayName = 'TySelect';
209
+
210
+ // ============================================================================
211
+ // TySelectedTags — out-of-band chip display for a TySelect
212
+ // ============================================================================
213
+
214
+ export interface TySelectedTagsProps extends React.HTMLAttributes<HTMLElement> {
215
+ /** id of the ty-select to display. Falls back to the previous element sibling. */
216
+ htmlFor?: string;
217
+ /** Optional <template> child as chip blueprint ({value}/{label}/{flavor}/{data-*} placeholders) */
218
+ children?: React.ReactNode;
219
+ }
220
+
221
+ // React wrapper for ty-selected-tags web component
222
+ export const TySelectedTags = React.forwardRef<HTMLElement, TySelectedTagsProps>(
223
+ ({ htmlFor, children, ...props }, ref) => {
224
+ const elementRef = useRef<HTMLElement>(null);
225
+
226
+ useEffect(() => {
227
+ if (ref && elementRef.current) {
228
+ if (typeof ref === 'function') ref(elementRef.current);
229
+ else ref.current = elementRef.current;
230
+ }
231
+ }, [ref]);
232
+
233
+ const webComponentProps: Record<string, any> = { ...props, ref: elementRef };
234
+ if (htmlFor) webComponentProps.for = htmlFor;
235
+
236
+ return React.createElement('ty-selected-tags', webComponentProps, children);
237
+ }
238
+ );
239
+
240
+ TySelectedTags.displayName = 'TySelectedTags';
@@ -44,9 +44,6 @@ export type { TyInputProps, TyInputEventDetail, TyInputCSSProperties } from './T
44
44
  export { TyTextarea } from './TyTextarea';
45
45
  export type { TyTextareaProps, TyTextareaEventDetail } from './TyTextarea';
46
46
 
47
- export { TyDropdown } from './TyDropdown';
48
- export type { TyDropdownProps, TyDropdownEventDetail } from './TyDropdown';
49
-
50
47
  export { TyOption } from './TyOption';
51
48
  export type { TyOptionProps } from './TyOption';
52
49
 
@@ -55,12 +52,15 @@ export type { TyIconProps } from './TyIcon';
55
52
 
56
53
  export { TyModal } from './TyModal';
57
54
  export type { TyModalProps, TyModalEventDetail, TyModalRef } from './TyModal';
55
+ // Platform/ARIA name alias (the element is also registered as ty-dialog)
56
+ export { TyModal as TyDialog } from './TyModal';
57
+ export type { TyModalProps as TyDialogProps, TyModalEventDetail as TyDialogEventDetail, TyModalRef as TyDialogRef } from './TyModal';
58
58
 
59
59
  export { TyTooltip } from './TyTooltip';
60
60
  export type { TyTooltipProps } from './TyTooltip';
61
61
 
62
- export { TyMultiselect } from './TyMultiselect';
63
- export type { TyMultiselectProps, TyMultiselectEventDetail } from './TyMultiselect';
62
+ export { TySelect, TySelectedTags } from './TySelect';
63
+ export type { TySelectProps, TySelectEventDetail, TySelectItem, TySelectedTagsProps } from './TySelect';
64
64
 
65
65
  export { TyCalendar } from './TyCalendar';
66
66
  export type { TyCalendarProps, TyCalendarChangeEventDetail, TyCalendarNavigateEventDetail } from './TyCalendar';
@@ -85,6 +85,9 @@ export type { TyRadioGroupProps, TyRadioGroupEventDetail } from './TyRadioGroup'
85
85
 
86
86
  export { TyCopy } from './TyCopy';
87
87
  export type { TyCopyProps } from './TyCopy';
88
+ // Descriptive name alias (the element is also registered as ty-copy-field)
89
+ export { TyCopy as TyCopyField } from './TyCopy';
90
+ export type { TyCopyProps as TyCopyFieldProps } from './TyCopy';
88
91
 
89
92
  export { TyFileUpload } from './TyFileUpload';
90
93
  export type { TyFileUploadProps, TyFileUploadEventDetail } from './TyFileUpload';
@@ -122,12 +125,10 @@ export { TyButton as Button } from './TyButton';
122
125
  export { TyTag as Tag } from './TyTag';
123
126
  export { TyInput as Input } from './TyInput';
124
127
  export { TyTextarea as Textarea } from './TyTextarea';
125
- export { TyDropdown as Dropdown } from './TyDropdown';
126
128
  export { TyOption as Option } from './TyOption';
127
129
  export { TyIcon as Icon } from './TyIcon';
128
130
  export { TyModal as Modal } from './TyModal';
129
131
  export { TyTooltip as Tooltip } from './TyTooltip';
130
- export { TyMultiselect as Multiselect } from './TyMultiselect';
131
132
  export { TyCalendar as Calendar } from './TyCalendar';
132
133
  export { TyDatePicker as DatePicker } from './TyDatePicker';
133
134
  export { TyPopup as Popup } from './TyPopup';
@@ -162,9 +163,6 @@ export type { TyInputProps as InputProps, TyInputEventDetail as InputEventDetail
162
163
  // Textarea types
163
164
  export type { TyTextareaProps as TextareaProps, TyTextareaEventDetail as TextareaEventDetail } from './TyTextarea';
164
165
 
165
- // Dropdown types
166
- export type { TyDropdownProps as DropdownProps, TyDropdownEventDetail as DropdownEventDetail, OptionData } from './TyDropdown';
167
-
168
166
  // Option types
169
167
  export type { TyOptionProps as OptionProps } from './TyOption';
170
168
 
@@ -177,9 +175,6 @@ export type { TyModalProps as ModalProps, TyModalEventDetail as ModalEventDetail
177
175
  // Tooltip types
178
176
  export type { TyTooltipProps as TooltipProps } from './TyTooltip';
179
177
 
180
- // Multiselect types
181
- export type { TyMultiselectProps as MultiselectProps, TyMultiselectEventDetail as MultiselectEventDetail } from './TyMultiselect';
182
-
183
178
  // Calendar types
184
179
  export type { TyCalendarProps as CalendarProps, TyCalendarChangeEventDetail as CalendarChangeEventDetail, TyCalendarNavigateEventDetail as CalendarNavigateEventDetail } from './TyCalendar';
185
180
 
package/src/version.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  // Run 'npm run generate:version' to regenerate.
4
4
 
5
5
  /** Current version of tyrell-react. Synced with package.json on build. */
6
- export const VERSION = '1.0.0-RC10'
6
+ export const VERSION = '1.0.0-RC12'
@@ -1,62 +0,0 @@
1
- import React from 'react';
2
- export interface OptionData {
3
- value: string;
4
- text: string;
5
- disabled?: boolean;
6
- }
7
- export interface TyDropdownEventDetail {
8
- option: HTMLElement;
9
- }
10
- export interface TyDropdownProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange' | 'style'> {
11
- style?: import('./TyInput').TyInputCSSProperties;
12
- /** Semantic styling variant */
13
- flavor?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'neutral';
14
- /** Dropdown size */
15
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
16
- /** Selected value */
17
- value?: string;
18
- /** Placeholder text */
19
- placeholder?: string;
20
- /** Dropdown label */
21
- label?: string;
22
- /** Disable the dropdown */
23
- disabled?: boolean;
24
- /**
25
- * Loading state — replaces the open popup options list with a centered
26
- * spinner. Search input stays usable. Pair with `externalSearch` while
27
- * fetching results from a parent-owned data source.
28
- */
29
- loading?: boolean;
30
- /** Make dropdown readonly */
31
- readonly?: boolean;
32
- /** Required field */
33
- required?: boolean;
34
- /** Show clear button */
35
- clearable?: boolean;
36
- /** Disable clear button (alias for clearable={false}) */
37
- notClearable?: boolean;
38
- /** Debounce in milliseconds (0-5000) */
39
- debounce?: number;
40
- /**
41
- * Switch to external (remote) search mode. Default is `false` — the dropdown
42
- * filters its options locally. When `true`, the dropdown stops filtering and
43
- * dispatches `search` events on each keystroke; the parent owns filtering
44
- * and updates the children.
45
- */
46
- externalSearch?: boolean;
47
- /** @deprecated Use `externalSearch` instead. */
48
- notSearchable?: boolean;
49
- /** @deprecated Use `externalSearch` instead. Pass `searchable={false}` was equivalent to `externalSearch={true}`. */
50
- searchable?: boolean;
51
- /** Form field name for form submission */
52
- name?: string;
53
- options?: OptionData[];
54
- onChange?: (event: CustomEvent<TyDropdownEventDetail>) => void;
55
- onSearch?: (event: CustomEvent<{
56
- query: string;
57
- element: HTMLElement;
58
- }>) => void;
59
- children?: React.ReactNode;
60
- }
61
- export declare const TyDropdown: React.ForwardRefExoticComponent<TyDropdownProps & React.RefAttributes<HTMLElement>>;
62
- //# sourceMappingURL=TyDropdown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TyDropdown.d.ts","sourceRoot":"","sources":["../../src/components/TyDropdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAK9D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,WAAW,CAAC;CACrB;AAGD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACpG,KAAK,CAAC,EAAE,OAAO,WAAW,EAAE,oBAAoB,CAAC;IACjD,+BAA+B;IAC/B,MAAM,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAEhF,oBAAoB;IACpB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAExC,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,yDAAyD;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,gDAAgD;IAChD,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,qHAAqH;IACrH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAGvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,qBAAqB,CAAC,KAAK,IAAI,CAAC;IAC/D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC,KAAK,IAAI,CAAC;IAGjF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAGD,eAAO,MAAM,UAAU,qFAqJtB,CAAC"}