diff --git a/native_uis/webf_cupertino_ui/lib/src/menu.d.ts b/native_uis/webf_cupertino_ui/lib/src/menu.d.ts new file mode 100644 index 0000000000..83f98a0e7f --- /dev/null +++ b/native_uis/webf_cupertino_ui/lib/src/menu.d.ts @@ -0,0 +1,53 @@ +/** + * Properties for . + * A tap-triggered popup menu wrapping Flutter's showMenu with Cupertino styling. + */ + +interface MenuAction { + /** Button label text. */ + text: string; + /** Optional trailing icon name (Cupertino icon key). */ + icon?: string; + /** Marks this action as destructive (red). */ + destructive?: boolean; + /** + * Optional event name associated with this action. + * If omitted, a name is derived from the text. + */ + event?: string; +} + +interface FlutterCupertinoMenuProperties { + /** + * Whether the menu trigger is disabled. + * When disabled, tapping the child will not open the menu. + * @default false + */ + disabled?: boolean; +} + +interface FlutterCupertinoMenuMethods { + /** + * Set the list of actions displayed in the popup menu. + */ + setActions(actions: MenuAction[]): void; +} + +interface FlutterCupertinoMenuSelectDetail { + /** Zero-based index of the selected action. */ + index: number; + /** Action text. */ + text: string; + /** Event name for this action. */ + event: string; + /** Whether the action is destructive. */ + destructive: boolean; +} + +interface FlutterCupertinoMenuEvents { + /** + * Fired when an action is selected. + * detail contains metadata about the selected action. + */ + select: CustomEvent; +} diff --git a/native_uis/webf_cupertino_ui/lib/src/menu.dart b/native_uis/webf_cupertino_ui/lib/src/menu.dart new file mode 100644 index 0000000000..0941dc9163 --- /dev/null +++ b/native_uis/webf_cupertino_ui/lib/src/menu.dart @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:webf/rendering.dart'; +import 'package:webf/webf.dart'; +import 'package:webf/dom.dart' as dom; + +import 'icon.dart'; +import 'menu_bindings_generated.dart'; +import 'logger.dart'; + +/// WebF custom element that provides a tap-triggered popup menu +/// with Cupertino styling. +/// +/// Exposed as `` in the DOM. +class FlutterCupertinoMenu extends FlutterCupertinoMenuBindings { + FlutterCupertinoMenu(super.context) { + _actions = >[]; + } + + bool _disabled = false; + List> _actions = >[]; + + @override + bool get disabled => _disabled; + + @override + set disabled(value) { + final bool next = value == true; + if (next != _disabled) { + _disabled = next; + state?.requestUpdateState(() {}); + } + } + + @override + bool get allowsInfiniteHeight => true; + + @override + bool get allowsInfiniteWidth => true; + + static StaticDefinedSyncBindingObjectMethodMap menuMethods = { + 'setActions': StaticDefinedSyncBindingObjectMethod( + call: (element, args) { + final menu = castToType(element); + + if (args.isNotEmpty) { + final actionsData = args[0]; + + if (actionsData is List) { + final List> newActions = >[]; + for (final item in actionsData) { + if (item is Map) { + newActions.add( + Map.from( + item.map((key, value) => MapEntry(key.toString(), value)), + ), + ); + } else { + logger.w('Skipping non-map item in actions list: $item'); + } + } + menu._actions = newActions; + } else { + menu._actions = >[]; + } + menu.state?.requestUpdateState(() {}); + } else { + menu._actions = >[]; + menu.state?.requestUpdateState(() {}); + } + }, + ), + }; + + @override + List get methods => + [ + ...super.methods, + menuMethods, + ]; + + IconData? _getIconData(String iconName) { + final IconData? icon = FlutterCupertinoIcon.getIconType(iconName); + if (icon == null) { + logger.w('Icon not found for name: $iconName'); + } + return icon; + } + + @override + FlutterCupertinoMenuState? get state => + super.state as FlutterCupertinoMenuState?; + + @override + WebFWidgetElementState createState() { + return FlutterCupertinoMenuState(this); + } +} + +class FlutterCupertinoMenuState extends WebFWidgetElementState { + FlutterCupertinoMenuState(super.widgetElement); + + @override + FlutterCupertinoMenu get widgetElement => + super.widgetElement as FlutterCupertinoMenu; + + Widget? _findChild() { + for (final child in widgetElement.childNodes) { + if (child is dom.Element) { + return WebFWidgetElementChild(child: child.toWidget()); + } + } + return null; + } + + Future _showMenu() async { + if (widgetElement._disabled || widgetElement._actions.isEmpty) return; + + final RenderBox renderBox = context.findRenderObject() as RenderBox; + final Offset offset = renderBox.localToGlobal(Offset.zero); + final Size size = renderBox.size; + + final List> items = >[]; + for (int i = 0; i < widgetElement._actions.length; i++) { + final Map action = widgetElement._actions[i]; + final bool isDestructive = action['destructive'] == true; + final String text = action['text'] as String? ?? ''; + final String? iconName = action['icon'] as String?; + + items.add( + PopupMenuItem( + value: i, + child: Row( + children: [ + Expanded( + child: Text( + text, + style: TextStyle( + color: isDestructive ? CupertinoColors.destructiveRed : null, + fontSize: 17, + ), + ), + ), + if (iconName != null) + Padding( + padding: const EdgeInsets.only(left: 8), + child: Icon( + widgetElement._getIconData(iconName), + size: 20, + color: isDestructive ? CupertinoColors.destructiveRed : null, + ), + ), + ], + ), + ), + ); + } + + final int? selected = await showMenu( + context: context, + position: RelativeRect.fromLTRB( + offset.dx, + offset.dy + size.height, + offset.dx + size.width, + offset.dy + size.height, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14), + ), + items: items, + ); + + if (selected != null && selected < widgetElement._actions.length) { + final Map action = widgetElement._actions[selected]; + final String text = action['text'] as String? ?? ''; + final bool isDestructive = action['destructive'] == true; + final String eventName = action['event'] as String? ?? + text.toLowerCase().replaceAll(' ', '_'); + + final Map detail = { + 'index': selected, + 'text': text, + 'event': eventName, + 'destructive': isDestructive, + }; + + widgetElement.dispatchEvent(CustomEvent('select', detail: detail)); + } + } + + @override + Widget build(BuildContext context) { + final Widget? child = _findChild(); + + if (child == null) { + return const SizedBox.shrink(); + } + + return GestureDetector( + onTap: widgetElement._disabled ? null : _showMenu, + child: child, + ); + } +} diff --git a/native_uis/webf_cupertino_ui/lib/src/menu_bindings_generated.dart b/native_uis/webf_cupertino_ui/lib/src/menu_bindings_generated.dart new file mode 100644 index 0000000000..617339d8b8 --- /dev/null +++ b/native_uis/webf_cupertino_ui/lib/src/menu_bindings_generated.dart @@ -0,0 +1,36 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `webf codegen` +// ignore_for_file: avoid_unused_constructor_parameters +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: implementation_imports +// ignore_for_file: library_private_types_in_public_api +// ignore_for_file: prefer_void_to_null +import 'package:webf/webf.dart'; +abstract class FlutterCupertinoMenuBindings extends WidgetElement { + FlutterCupertinoMenuBindings(super.context); + bool get disabled; + set disabled(value); + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (value) => disabled = value == 'true' || value == '', + deleter: () => disabled = false + ); + } + static StaticDefinedBindingPropertyMap flutterCupertinoMenuProperties = { + 'disabled': StaticDefinedBindingProperty( + getter: (element) => castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = value, + ), + }; + @override + List get properties => [ + ...super.properties, + flutterCupertinoMenuProperties, + ]; +} diff --git a/native_uis/webf_cupertino_ui/lib/webf_cupertino_ui.dart b/native_uis/webf_cupertino_ui/lib/webf_cupertino_ui.dart index b830dee6fa..afc1d858ac 100644 --- a/native_uis/webf_cupertino_ui/lib/webf_cupertino_ui.dart +++ b/native_uis/webf_cupertino_ui/lib/webf_cupertino_ui.dart @@ -20,6 +20,7 @@ export 'src/form_section.dart'; export 'src/input.dart'; export 'src/search_text_field.dart'; export 'src/date_picker.dart'; +export 'src/menu.dart'; import 'src/alert.dart'; import 'src/action_sheet.dart'; import 'src/context_menu.dart'; @@ -41,6 +42,7 @@ import 'src/tab_view.dart'; import 'src/sliding_segmented_control.dart'; import 'src/list_tile.dart'; import 'src/search_text_field.dart'; +import 'src/menu.dart'; /// Installs all Cupertino UI custom elements for WebF. /// @@ -106,6 +108,9 @@ void installWebFCupertinoUI() { WebF.defineCustomElement( 'flutter-cupertino-date-picker', (context) => FlutterCupertinoDatePicker(context)); + WebF.defineCustomElement( + 'flutter-cupertino-menu', + (context) => FlutterCupertinoMenu(context)); // WebF.defineCustomElement('flutter-cupertino-input', (context) => FlutterCupertinoInput(context)); diff --git a/native_uis/webf_shadcn_ui/IMPLEMENTATION_STATUS.md b/native_uis/webf_shadcn_ui/IMPLEMENTATION_STATUS.md index fa16f55885..1e762db91d 100644 --- a/native_uis/webf_shadcn_ui/IMPLEMENTATION_STATUS.md +++ b/native_uis/webf_shadcn_ui/IMPLEMENTATION_STATUS.md @@ -29,7 +29,7 @@ native_uis/webf_shadcn_ui/ | Input | `` | input.dart | input.d.ts | Done | | Textarea | `` | textarea.dart | textarea.d.ts | Done | | Checkbox | `` | checkbox.dart | checkbox.d.ts | Done | -| Radio | `` | radio.dart | radio.d.ts | Done | +| RadioGroup | `` | radio_group.dart | radio_group.d.ts | Done | | Switch | `` | switch.dart | switch.d.ts | Done | | Select | `` | select.dart | select.d.ts | Done | | Slider | `` | slider.dart | slider.d.ts | Done | @@ -144,7 +144,7 @@ The following slot elements are implemented for compositional components: - `` ### Other Slots -- `` +- `` - `` - `` - `` diff --git a/native_uis/webf_shadcn_ui/README.md b/native_uis/webf_shadcn_ui/README.md index 68b77673ce..3457799b8b 100644 --- a/native_uis/webf_shadcn_ui/README.md +++ b/native_uis/webf_shadcn_ui/README.md @@ -58,7 +58,7 @@ void main() { - `` - Text input field - `` - Multi-line text input - `` - Checkbox control -- `` - Radio button group +- `` - Radio button group - `` - Toggle switch - `` - Dropdown select - `` - Range slider diff --git a/native_uis/webf_shadcn_ui/lib/src/components/accordion_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/accordion_bindings_generated.dart index 2b709c349e..6e918b5639 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/accordion_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/accordion_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnAccordionBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['type'] = ElementAttributeProperty( getter: () => type?.toString(), - setter: (value) => this.type = value, + setter: (value) => type = value, deleter: () => type = null ); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['collapsible'] = ElementAttributeProperty( getter: () => collapsible.toString(), - setter: (value) => this.collapsible = value == 'true' || value == '', + setter: (value) => collapsible = value == 'true' || value == '', deleter: () => collapsible = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/alert_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/alert_bindings_generated.dart index 083d946088..cc19ef5650 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/alert_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/alert_bindings_generated.dart @@ -19,12 +19,12 @@ abstract class FlutterShadcnAlertBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.toString(), - setter: (value) => this.variant = value, + setter: (value) => variant = value, deleter: () => variant = null ); attributes['icon'] = ElementAttributeProperty( getter: () => icon?.toString(), - setter: (value) => this.icon = value, + setter: (value) => icon = value, deleter: () => icon = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/avatar_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/avatar_bindings_generated.dart index 3e89eb61b2..b7f915709e 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/avatar_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/avatar_bindings_generated.dart @@ -23,22 +23,22 @@ abstract class FlutterShadcnAvatarBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['src'] = ElementAttributeProperty( getter: () => src?.toString(), - setter: (value) => this.src = value, + setter: (value) => src = value, deleter: () => src = null ); attributes['alt'] = ElementAttributeProperty( getter: () => alt?.toString(), - setter: (value) => this.alt = value, + setter: (value) => alt = value, deleter: () => alt = null ); attributes['fallback'] = ElementAttributeProperty( getter: () => fallback?.toString(), - setter: (value) => this.fallback = value, + setter: (value) => fallback = value, deleter: () => fallback = null ); attributes['size'] = ElementAttributeProperty( getter: () => size?.toString(), - setter: (value) => this.size = value, + setter: (value) => size = value, deleter: () => size = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/badge_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/badge_bindings_generated.dart index 4497f88010..03ab361024 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/badge_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/badge_bindings_generated.dart @@ -17,7 +17,7 @@ abstract class FlutterShadcnBadgeBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.toString(), - setter: (value) => this.variant = value, + setter: (value) => variant = value, deleter: () => variant = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/breadcrumb_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/breadcrumb_bindings_generated.dart index 7262103791..520842caa4 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/breadcrumb_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/breadcrumb_bindings_generated.dart @@ -37,12 +37,12 @@ abstract class FlutterShadcnBreadcrumbBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['spacing'] = ElementAttributeProperty( getter: () => spacing?.toString(), - setter: (value) => this.spacing = double.tryParse(value) ?? 0.0, + setter: (value) => spacing = double.tryParse(value) ?? 0.0, deleter: () => spacing = 0.0 ); attributes['separator'] = ElementAttributeProperty( getter: () => separator?.value, - setter: (value) => this.separator = FlutterShadcnBreadcrumbSeparator.parse(value), + setter: (value) => separator = FlutterShadcnBreadcrumbSeparator.parse(value), deleter: () => separator = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/button_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/button_bindings_generated.dart index 6184a0a4d8..514c72f8d3 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/button_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/button_bindings_generated.dart @@ -25,27 +25,27 @@ abstract class FlutterShadcnButtonBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.toString(), - setter: (value) => this.variant = value, + setter: (value) => variant = value, deleter: () => variant = null ); attributes['size'] = ElementAttributeProperty( getter: () => size?.toString(), - setter: (value) => this.size = value, + setter: (value) => size = value, deleter: () => size = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['loading'] = ElementAttributeProperty( getter: () => loading.toString(), - setter: (value) => this.loading = value == 'true' || value == '', + setter: (value) => loading = value == 'true' || value == '', deleter: () => loading = false ); attributes['icon'] = ElementAttributeProperty( getter: () => icon?.toString(), - setter: (value) => this.icon = value, + setter: (value) => icon = value, deleter: () => icon = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/calendar_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/calendar_bindings_generated.dart index 9bc3124bd7..78dc042e48 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/calendar_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/calendar_bindings_generated.dart @@ -74,67 +74,67 @@ abstract class FlutterShadcnCalendarBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['mode'] = ElementAttributeProperty( getter: () => mode?.value, - setter: (value) => this.mode = FlutterShadcnCalendarMode.parse(value), + setter: (value) => mode = FlutterShadcnCalendarMode.parse(value), deleter: () => mode = null ); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['min'] = ElementAttributeProperty( getter: () => min?.toString(), - setter: (value) => this.min = value, + setter: (value) => min = value, deleter: () => min = null ); attributes['max'] = ElementAttributeProperty( getter: () => max?.toString(), - setter: (value) => this.max = value, + setter: (value) => max = value, deleter: () => max = null ); attributes['caption-layout'] = ElementAttributeProperty( getter: () => captionLayout?.value, - setter: (value) => this.captionLayout = FlutterShadcnCalendarCaptionLayout.parse(value), + setter: (value) => captionLayout = FlutterShadcnCalendarCaptionLayout.parse(value), deleter: () => captionLayout = null ); attributes['hide-navigation'] = ElementAttributeProperty( getter: () => hideNavigation.toString(), - setter: (value) => this.hideNavigation = value == 'true' || value == '', + setter: (value) => hideNavigation = value == 'true' || value == '', deleter: () => hideNavigation = false ); attributes['show-week-numbers'] = ElementAttributeProperty( getter: () => showWeekNumbers.toString(), - setter: (value) => this.showWeekNumbers = value == 'true' || value == '', + setter: (value) => showWeekNumbers = value == 'true' || value == '', deleter: () => showWeekNumbers = false ); attributes['show-outside-days'] = ElementAttributeProperty( getter: () => showOutsideDays.toString(), - setter: (value) => this.showOutsideDays = value == 'true' || value == '', + setter: (value) => showOutsideDays = value == 'true' || value == '', deleter: () => showOutsideDays = false ); attributes['fixed-weeks'] = ElementAttributeProperty( getter: () => fixedWeeks.toString(), - setter: (value) => this.fixedWeeks = value == 'true' || value == '', + setter: (value) => fixedWeeks = value == 'true' || value == '', deleter: () => fixedWeeks = false ); attributes['hide-weekday-names'] = ElementAttributeProperty( getter: () => hideWeekdayNames.toString(), - setter: (value) => this.hideWeekdayNames = value == 'true' || value == '', + setter: (value) => hideWeekdayNames = value == 'true' || value == '', deleter: () => hideWeekdayNames = false ); attributes['number-of-months'] = ElementAttributeProperty( getter: () => numberOfMonths?.toString(), - setter: (value) => this.numberOfMonths = double.tryParse(value) ?? 0.0, + setter: (value) => numberOfMonths = double.tryParse(value) ?? 0.0, deleter: () => numberOfMonths = 0.0 ); attributes['allow-deselection'] = ElementAttributeProperty( getter: () => allowDeselection.toString(), - setter: (value) => this.allowDeselection = value == 'true' || value == '', + setter: (value) => allowDeselection = value == 'true' || value == '', deleter: () => allowDeselection = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/checkbox_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/checkbox_bindings_generated.dart index 9ec18afde8..10a9765d80 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/checkbox_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/checkbox_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnCheckboxBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['checked'] = ElementAttributeProperty( getter: () => checked.toString(), - setter: (value) => this.checked = value == 'true' || value == '', + setter: (value) => checked = value == 'true' || value == '', deleter: () => checked = false ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['indeterminate'] = ElementAttributeProperty( getter: () => indeterminate.toString(), - setter: (value) => this.indeterminate = value == 'true' || value == '', + setter: (value) => indeterminate = value == 'true' || value == '', deleter: () => indeterminate = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/collapsible.dart b/native_uis/webf_shadcn_ui/lib/src/components/collapsible.dart index 6c7e4b5ae7..07064f4ca0 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/collapsible.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/collapsible.dart @@ -51,6 +51,8 @@ class FlutterShadcnCollapsible extends FlutterShadcnCollapsibleBindings { class FlutterShadcnCollapsibleState extends WebFWidgetElementState { FlutterShadcnCollapsibleState(super.widgetElement); + Offset? _tapDownPosition; + @override FlutterShadcnCollapsible get widgetElement => super.widgetElement as FlutterShadcnCollapsible; @@ -74,12 +76,30 @@ class FlutterShadcnCollapsibleState extends WebFWidgetElementState { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (trigger != null) - GestureDetector( - onTap: widgetElement.disabled + // Use Listener instead of GestureDetector to avoid gesture arena + // conflicts with interactive child widgets (e.g. ShadButton). + Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: widgetElement.disabled + ? null + : (event) { + _tapDownPosition = event.position; + }, + onPointerUp: widgetElement.disabled ? null - : () { - widgetElement.open = !widgetElement.open; + : (event) { + if (_tapDownPosition != null) { + final distance = + (event.position - _tapDownPosition!).distance; + _tapDownPosition = null; + if (distance < 20) { + widgetElement.open = !widgetElement.open; + } + } }, + onPointerCancel: (_) { + _tapDownPosition = null; + }, child: trigger, ), if (widgetElement.open && content != null) content, diff --git a/native_uis/webf_shadcn_ui/lib/src/components/collapsible_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/collapsible_bindings_generated.dart index c60aa8957a..17e9128e55 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/collapsible_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/collapsible_bindings_generated.dart @@ -19,12 +19,12 @@ abstract class FlutterShadcnCollapsibleBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/combobox_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/combobox_bindings_generated.dart index 667c557b77..8062af8c57 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/combobox_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/combobox_bindings_generated.dart @@ -27,32 +27,32 @@ abstract class FlutterShadcnComboboxBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['search-placeholder'] = ElementAttributeProperty( getter: () => searchPlaceholder?.toString(), - setter: (value) => this.searchPlaceholder = value, + setter: (value) => searchPlaceholder = value, deleter: () => searchPlaceholder = null ); attributes['empty-text'] = ElementAttributeProperty( getter: () => emptyText?.toString(), - setter: (value) => this.emptyText = value, + setter: (value) => emptyText = value, deleter: () => emptyText = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['clearable'] = ElementAttributeProperty( getter: () => clearable.toString(), - setter: (value) => this.clearable = value == 'true' || value == '', + setter: (value) => clearable = value == 'true' || value == '', deleter: () => clearable = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/context_menu_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/context_menu_bindings_generated.dart index 3fa578d47f..67f1823396 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/context_menu_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/context_menu_bindings_generated.dart @@ -17,7 +17,7 @@ abstract class FlutterShadcnContextMenuBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/date_picker_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/date_picker_bindings_generated.dart index ea847cc407..f2a1488aa7 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/date_picker_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/date_picker_bindings_generated.dart @@ -23,22 +23,22 @@ abstract class FlutterShadcnDatePickerBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['format'] = ElementAttributeProperty( getter: () => format?.toString(), - setter: (value) => this.format = value, + setter: (value) => format = value, deleter: () => format = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/dialog_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/dialog_bindings_generated.dart index adcbf779b8..a9203b5eb4 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/dialog_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/dialog_bindings_generated.dart @@ -19,12 +19,12 @@ abstract class FlutterShadcnDialogBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); attributes['close-on-outside-click'] = ElementAttributeProperty( getter: () => closeOnOutsideClick.toString(), - setter: (value) => this.closeOnOutsideClick = value == 'true' || value == '', + setter: (value) => closeOnOutsideClick = value == 'true' || value == '', deleter: () => closeOnOutsideClick = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu.dart b/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu.dart index 6a12d313e0..49e697451b 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu.dart @@ -44,6 +44,7 @@ class FlutterShadcnDropdownMenuState extends WebFWidgetElementState { FlutterShadcnDropdownMenuState(super.widgetElement); final _popoverController = ShadPopoverController(); + Offset? _tapDownPosition; @override FlutterShadcnDropdownMenu get widgetElement => @@ -87,9 +88,24 @@ class FlutterShadcnDropdownMenuState extends WebFWidgetElementState { return ShadPopover( controller: _popoverController, popover: (context) => content ?? const SizedBox.shrink(), - child: GestureDetector( - onTap: () { - widgetElement.open = !widgetElement.open; + // Use Listener instead of GestureDetector to avoid gesture arena + // conflicts with interactive child widgets (e.g. ShadButton). + child: Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (event) { + _tapDownPosition = event.position; + }, + onPointerUp: (event) { + if (_tapDownPosition != null) { + final distance = (event.position - _tapDownPosition!).distance; + _tapDownPosition = null; + if (distance < 20) { + widgetElement.open = !widgetElement.open; + } + } + }, + onPointerCancel: (_) { + _tapDownPosition = null; }, child: trigger, ), diff --git a/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu_bindings_generated.dart index 84e3e2a934..d3e66cdfb8 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/dropdown_menu_bindings_generated.dart @@ -17,7 +17,7 @@ abstract class FlutterShadcnDropdownMenuBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/form_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/form_bindings_generated.dart index 0180492924..2af252a3d2 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/form_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/form_bindings_generated.dart @@ -38,17 +38,17 @@ abstract class FlutterShadcnFormBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['auto-validate-mode'] = ElementAttributeProperty( getter: () => autoValidateMode?.value, - setter: (value) => this.autoValidateMode = FlutterShadcnFormAutoValidateMode.parse(value), + setter: (value) => autoValidateMode = FlutterShadcnFormAutoValidateMode.parse(value), deleter: () => autoValidateMode = null ); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); } @@ -74,47 +74,4 @@ abstract class FlutterShadcnFormBindings extends WidgetElement { ...super.properties, flutterShadcnFormProperties, ]; - bool validate(List args); - bool submit(List args); - void reset(List args); - dynamic getFieldValue(List args); - void setFieldValue(List args); - void setFieldError(List args); - static StaticDefinedSyncBindingObjectMethodMap flutterShadcnFormMethods = { - 'validate': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).validate(args); - }, - ), - 'submit': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).submit(args); - }, - ), - 'reset': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).reset(args); - }, - ), - 'getFieldValue': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).getFieldValue(args); - }, - ), - 'setFieldValue': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).setFieldValue(args); - }, - ), - 'setFieldError': StaticDefinedSyncBindingObjectMethod( - call: (element, args) { - return castToType(element).setFieldError(args); - }, - ), - }; - @override - List get methods => [ - ...super.methods, - flutterShadcnFormMethods, - ]; } \ No newline at end of file diff --git a/native_uis/webf_shadcn_ui/lib/src/components/icon_button_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/icon_button_bindings_generated.dart index 67e702a816..d55e32d88e 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/icon_button_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/icon_button_bindings_generated.dart @@ -43,27 +43,27 @@ abstract class FlutterShadcnIconButtonBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.value, - setter: (value) => this.variant = FlutterShadcnIconButtonVariant.parse(value), + setter: (value) => variant = FlutterShadcnIconButtonVariant.parse(value), deleter: () => variant = null ); attributes['icon'] = ElementAttributeProperty( getter: () => icon?.toString(), - setter: (value) => this.icon = value, + setter: (value) => icon = value, deleter: () => icon = null ); attributes['icon-size'] = ElementAttributeProperty( getter: () => iconSize?.toString(), - setter: (value) => this.iconSize = double.tryParse(value) ?? 0.0, + setter: (value) => iconSize = double.tryParse(value) ?? 0.0, deleter: () => iconSize = 0.0 ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['loading'] = ElementAttributeProperty( getter: () => loading.toString(), - setter: (value) => this.loading = value == 'true' || value == '', + setter: (value) => loading = value == 'true' || value == '', deleter: () => loading = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/image_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/image_bindings_generated.dart index 0d4ea2c0a3..03e821342e 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/image_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/image_bindings_generated.dart @@ -25,27 +25,27 @@ abstract class FlutterShadcnImageBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['src'] = ElementAttributeProperty( getter: () => src?.toString(), - setter: (value) => this.src = value, + setter: (value) => src = value, deleter: () => src = null ); attributes['alt'] = ElementAttributeProperty( getter: () => alt?.toString(), - setter: (value) => this.alt = value, + setter: (value) => alt = value, deleter: () => alt = null ); attributes['width'] = ElementAttributeProperty( getter: () => width?.toString(), - setter: (value) => this.width = value, + setter: (value) => width = value, deleter: () => width = null ); attributes['height'] = ElementAttributeProperty( getter: () => height?.toString(), - setter: (value) => this.height = value, + setter: (value) => height = value, deleter: () => height = null ); attributes['fit'] = ElementAttributeProperty( getter: () => fit?.toString(), - setter: (value) => this.fit = value, + setter: (value) => fit = value, deleter: () => fit = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input.d.ts b/native_uis/webf_shadcn_ui/lib/src/components/input.d.ts index ed171b4aa1..7830b7450e 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/input.d.ts +++ b/native_uis/webf_shadcn_ui/lib/src/components/input.d.ts @@ -69,6 +69,64 @@ interface FlutterShadcnInputProperties { * Autofocus on mount. */ autofocus?: boolean; + + /** + * Text alignment within the input. + * Options: 'start', 'end', 'left', 'right', 'center' + * Default: 'start' + */ + textalign?: string; + + /** + * Controls automatic text capitalization behavior. + * Options: 'none', 'sentences', 'words', 'characters' + * Default: 'none' + */ + autocapitalize?: string; + + /** + * Whether to enable autocorrect. + * Default: true + */ + autocorrect?: boolean; + + /** + * Whether to show input suggestions. + * Default: true + */ + enablesuggestions?: boolean; + + /** + * Hint for the keyboard action button. + * Options: 'done', 'go', 'next', 'search', 'send', 'previous', 'newline' + */ + enterkeyhint?: string; + + /** + * Maximum number of lines for the input. Use for multi-line input. + */ + maxlines?: string; + + /** + * Minimum number of lines for the input. + */ + minlines?: string; + + /** + * Color of the cursor (e.g., '#FF0000', 'red'). + */ + cursorcolor?: string; + + /** + * Color of the text selection highlight (e.g., '#0000FF', 'blue'). + */ + selectioncolor?: string; + + /** + * Character used to obscure text in password mode. + * Default: '•' + */ + obscuringcharacter?: string; } /** @@ -86,4 +144,7 @@ interface FlutterShadcnInputEvents { /** Fired when input loses focus. */ blur: Event; + + /** Fired when the user submits the input (e.g., presses Enter/Done). */ + submit: Event; } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input.dart b/native_uis/webf_shadcn_ui/lib/src/components/input.dart index ff6c040af7..7796903020 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/input.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/input.dart @@ -26,6 +26,16 @@ class FlutterShadcnInput extends FlutterShadcnInputBindings { String? _pattern; bool _required = false; bool _autofocus = false; + TextAlign _textAlign = TextAlign.start; + TextCapitalization _textCapitalization = TextCapitalization.none; + bool _autocorrect = true; + bool _enableSuggestions = true; + TextInputAction? _textInputAction; + int? _maxLines = 1; + int? _minLines; + Color? _cursorColor; + Color? _selectionColor; + String _obscuringCharacter = '•'; @override String get value => _value; @@ -144,6 +154,233 @@ class FlutterShadcnInput extends FlutterShadcnInputBindings { } } + @override + String get textalign => _textAlign.name; + + @override + set textalign(value) { + final newValue = _parseTextAlign(value?.toString() ?? 'start'); + if (newValue != _textAlign) { + _textAlign = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String get autocapitalize => _textCapitalizationToString(_textCapitalization); + + @override + set autocapitalize(value) { + final newValue = _parseTextCapitalization(value?.toString() ?? 'none'); + if (newValue != _textCapitalization) { + _textCapitalization = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + bool get autocorrect => _autocorrect; + + @override + set autocorrect(value) { + final newValue = value != false; + if (newValue != _autocorrect) { + _autocorrect = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + bool get enablesuggestions => _enableSuggestions; + + @override + set enablesuggestions(value) { + final newValue = value != false; + if (newValue != _enableSuggestions) { + _enableSuggestions = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get enterkeyhint => + _textInputAction != null ? _textInputActionToString(_textInputAction!) : null; + + @override + set enterkeyhint(value) { + final newValue = value != null ? _parseTextInputAction(value.toString()) : null; + if (newValue != _textInputAction) { + _textInputAction = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get maxlines => _maxLines?.toString(); + + @override + set maxlines(value) { + final newValue = value != null ? int.tryParse(value.toString()) : null; + if (newValue != _maxLines) { + _maxLines = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get minlines => _minLines?.toString(); + + @override + set minlines(value) { + final newValue = value != null ? int.tryParse(value.toString()) : null; + if (newValue != _minLines) { + _minLines = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get cursorcolor => _cursorColor != null + ? '#${_cursorColor!.value.toRadixString(16).padLeft(8, '0')}' + : null; + + @override + set cursorcolor(value) { + final newValue = value != null ? _parseColor(value.toString()) : null; + if (newValue != _cursorColor) { + _cursorColor = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get selectioncolor => _selectionColor != null + ? '#${_selectionColor!.value.toRadixString(16).padLeft(8, '0')}' + : null; + + @override + set selectioncolor(value) { + final newValue = value != null ? _parseColor(value.toString()) : null; + if (newValue != _selectionColor) { + _selectionColor = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String get obscuringcharacter => _obscuringCharacter; + + @override + set obscuringcharacter(value) { + final newValue = value?.toString() ?? '•'; + if (newValue.isNotEmpty && newValue != _obscuringCharacter) { + _obscuringCharacter = newValue.characters.first; + state?.requestUpdateState(() {}); + } + } + + // --- Parsing helpers --- + + static TextAlign _parseTextAlign(String value) { + switch (value.toLowerCase()) { + case 'left': + return TextAlign.left; + case 'right': + return TextAlign.right; + case 'center': + return TextAlign.center; + case 'end': + return TextAlign.end; + case 'start': + default: + return TextAlign.start; + } + } + + static TextCapitalization _parseTextCapitalization(String value) { + switch (value.toLowerCase()) { + case 'sentences': + return TextCapitalization.sentences; + case 'words': + return TextCapitalization.words; + case 'characters': + return TextCapitalization.characters; + case 'none': + default: + return TextCapitalization.none; + } + } + + static String _textCapitalizationToString(TextCapitalization value) { + switch (value) { + case TextCapitalization.sentences: + return 'sentences'; + case TextCapitalization.words: + return 'words'; + case TextCapitalization.characters: + return 'characters'; + case TextCapitalization.none: + return 'none'; + } + } + + static TextInputAction _parseTextInputAction(String value) { + switch (value.toLowerCase()) { + case 'done': + return TextInputAction.done; + case 'go': + return TextInputAction.go; + case 'next': + return TextInputAction.next; + case 'search': + return TextInputAction.search; + case 'send': + return TextInputAction.send; + case 'previous': + return TextInputAction.previous; + case 'newline': + return TextInputAction.newline; + default: + return TextInputAction.done; + } + } + + static String _textInputActionToString(TextInputAction value) { + switch (value) { + case TextInputAction.done: + return 'done'; + case TextInputAction.go: + return 'go'; + case TextInputAction.next: + return 'next'; + case TextInputAction.search: + return 'search'; + case TextInputAction.send: + return 'send'; + case TextInputAction.previous: + return 'previous'; + case TextInputAction.newline: + return 'newline'; + default: + return 'done'; + } + } + + static Color? _parseColor(String value) { + final trimmed = value.trim().toLowerCase(); + if (trimmed.startsWith('#')) { + final hex = trimmed.substring(1); + if (hex.length == 6) { + final intValue = int.tryParse(hex, radix: 16); + if (intValue != null) return Color(0xFF000000 | intValue); + } else if (hex.length == 8) { + final intValue = int.tryParse(hex, radix: 16); + if (intValue != null) return Color(intValue); + } + } + return null; + } + TextInputType get keyboardType { switch (_type.toLowerCase()) { case 'email': @@ -215,22 +452,56 @@ class FlutterShadcnInputState extends WebFWidgetElementState { ]; } + // Map textAlign to ShadInput's alignment + placeholderAlignment. + // ShadInput uses three separate alignment controls: + // textAlign -> text within EditableText + // alignment -> positions the EditableText widget in the Stack + // placeholderAlignment -> positions the placeholder Text in the Stack + AlignmentGeometry? widgetAlignment; + switch (widgetElement._textAlign) { + case TextAlign.center: + widgetAlignment = Alignment.topCenter; + break; + case TextAlign.right: + case TextAlign.end: + widgetAlignment = Alignment.topRight; + break; + default: + widgetAlignment = null; // ShadInput defaults to topLeft + } + return ShadInput( controller: _controller, focusNode: _focusNode, placeholder: widgetElement.placeholder != null ? Text(widgetElement.placeholder!) : null, + placeholderAlignment: widgetAlignment, + alignment: widgetAlignment, enabled: !widgetElement.disabled, readOnly: widgetElement.readonly, obscureText: widgetElement.obscureText, + obscuringCharacter: widgetElement._obscuringCharacter, keyboardType: widgetElement.keyboardType, + textInputAction: widgetElement._textInputAction, + textCapitalization: widgetElement._textCapitalization, + textAlign: widgetElement._textAlign, autofocus: widgetElement.autofocus, + autocorrect: widgetElement._autocorrect, + enableSuggestions: widgetElement._enableSuggestions, + maxLines: widgetElement._maxLines, + minLines: widgetElement._minLines, + cursorColor: widgetElement._cursorColor, + selectionColor: widgetElement._selectionColor, inputFormatters: inputFormatters, onChanged: (value) { widgetElement._value = value; widgetElement.dispatchEvent(Event('input')); }, + onSubmitted: (value) { + widgetElement._value = value; + widgetElement.dispatchEvent(Event('submit')); + }, ); } } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/input_bindings_generated.dart index 1108f93151..3526cc29c7 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/input_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/input_bindings_generated.dart @@ -30,59 +30,129 @@ abstract class FlutterShadcnInputBindings extends WidgetElement { set required(value); bool get autofocus; set autofocus(value); + String? get textalign; + set textalign(value); + String? get autocapitalize; + set autocapitalize(value); + bool get autocorrect; + set autocorrect(value); + bool get enablesuggestions; + set enablesuggestions(value); + String? get enterkeyhint; + set enterkeyhint(value); + String? get maxlines; + set maxlines(value); + String? get minlines; + set minlines(value); + String? get cursorcolor; + set cursorcolor(value); + String? get selectioncolor; + set selectioncolor(value); + String? get obscuringcharacter; + set obscuringcharacter(value); @override void initializeAttributes(Map attributes) { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['type'] = ElementAttributeProperty( getter: () => type?.toString(), - setter: (value) => this.type = value, + setter: (value) => type = value, deleter: () => type = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['readonly'] = ElementAttributeProperty( getter: () => readonly.toString(), - setter: (value) => this.readonly = value == 'true' || value == '', + setter: (value) => readonly = value == 'true' || value == '', deleter: () => readonly = false ); attributes['maxlength'] = ElementAttributeProperty( getter: () => maxlength?.toString(), - setter: (value) => this.maxlength = value, + setter: (value) => maxlength = value, deleter: () => maxlength = null ); attributes['minlength'] = ElementAttributeProperty( getter: () => minlength?.toString(), - setter: (value) => this.minlength = value, + setter: (value) => minlength = value, deleter: () => minlength = null ); attributes['pattern'] = ElementAttributeProperty( getter: () => pattern?.toString(), - setter: (value) => this.pattern = value, + setter: (value) => pattern = value, deleter: () => pattern = null ); attributes['required'] = ElementAttributeProperty( getter: () => required.toString(), - setter: (value) => this.required = value == 'true' || value == '', + setter: (value) => required = value == 'true' || value == '', deleter: () => required = false ); attributes['autofocus'] = ElementAttributeProperty( getter: () => autofocus.toString(), - setter: (value) => this.autofocus = value == 'true' || value == '', + setter: (value) => autofocus = value == 'true' || value == '', deleter: () => autofocus = false ); + attributes['textalign'] = ElementAttributeProperty( + getter: () => textalign?.toString(), + setter: (value) => textalign = value, + deleter: () => textalign = null + ); + attributes['autocapitalize'] = ElementAttributeProperty( + getter: () => autocapitalize?.toString(), + setter: (value) => autocapitalize = value, + deleter: () => autocapitalize = null + ); + attributes['autocorrect'] = ElementAttributeProperty( + getter: () => autocorrect.toString(), + setter: (value) => autocorrect = value == 'true' || value == '', + deleter: () => autocorrect = false + ); + attributes['enablesuggestions'] = ElementAttributeProperty( + getter: () => enablesuggestions.toString(), + setter: (value) => enablesuggestions = value == 'true' || value == '', + deleter: () => enablesuggestions = false + ); + attributes['enterkeyhint'] = ElementAttributeProperty( + getter: () => enterkeyhint?.toString(), + setter: (value) => enterkeyhint = value, + deleter: () => enterkeyhint = null + ); + attributes['maxlines'] = ElementAttributeProperty( + getter: () => maxlines?.toString(), + setter: (value) => maxlines = value, + deleter: () => maxlines = null + ); + attributes['minlines'] = ElementAttributeProperty( + getter: () => minlines?.toString(), + setter: (value) => minlines = value, + deleter: () => minlines = null + ); + attributes['cursorcolor'] = ElementAttributeProperty( + getter: () => cursorcolor?.toString(), + setter: (value) => cursorcolor = value, + deleter: () => cursorcolor = null + ); + attributes['selectioncolor'] = ElementAttributeProperty( + getter: () => selectioncolor?.toString(), + setter: (value) => selectioncolor = value, + deleter: () => selectioncolor = null + ); + attributes['obscuringcharacter'] = ElementAttributeProperty( + getter: () => obscuringcharacter?.toString(), + setter: (value) => obscuringcharacter = value, + deleter: () => obscuringcharacter = null + ); } static StaticDefinedBindingPropertyMap flutterShadcnInputProperties = { 'value': StaticDefinedBindingProperty( @@ -135,6 +205,56 @@ abstract class FlutterShadcnInputBindings extends WidgetElement { setter: (element, value) => castToType(element).autofocus = value, ), + 'textalign': StaticDefinedBindingProperty( + getter: (element) => castToType(element).textalign, + setter: (element, value) => + castToType(element).textalign = value, + ), + 'autocapitalize': StaticDefinedBindingProperty( + getter: (element) => castToType(element).autocapitalize, + setter: (element, value) => + castToType(element).autocapitalize = value, + ), + 'autocorrect': StaticDefinedBindingProperty( + getter: (element) => castToType(element).autocorrect, + setter: (element, value) => + castToType(element).autocorrect = value, + ), + 'enablesuggestions': StaticDefinedBindingProperty( + getter: (element) => castToType(element).enablesuggestions, + setter: (element, value) => + castToType(element).enablesuggestions = value, + ), + 'enterkeyhint': StaticDefinedBindingProperty( + getter: (element) => castToType(element).enterkeyhint, + setter: (element, value) => + castToType(element).enterkeyhint = value, + ), + 'maxlines': StaticDefinedBindingProperty( + getter: (element) => castToType(element).maxlines, + setter: (element, value) => + castToType(element).maxlines = value, + ), + 'minlines': StaticDefinedBindingProperty( + getter: (element) => castToType(element).minlines, + setter: (element, value) => + castToType(element).minlines = value, + ), + 'cursorcolor': StaticDefinedBindingProperty( + getter: (element) => castToType(element).cursorcolor, + setter: (element, value) => + castToType(element).cursorcolor = value, + ), + 'selectioncolor': StaticDefinedBindingProperty( + getter: (element) => castToType(element).selectioncolor, + setter: (element, value) => + castToType(element).selectioncolor = value, + ), + 'obscuringcharacter': StaticDefinedBindingProperty( + getter: (element) => castToType(element).obscuringcharacter, + setter: (element, value) => + castToType(element).obscuringcharacter = value, + ), }; @override List get properties => [ diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input_otp.d.ts b/native_uis/webf_shadcn_ui/lib/src/components/input_otp.d.ts new file mode 100644 index 0000000000..48580194f7 --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/input_otp.d.ts @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ + +/** + * Properties for + * + * Accessible one-time password input with individual character slots. + * + * @example + * ```html + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + */ +interface FlutterShadcnInputOtpProperties { + /** + * Maximum number of characters (required). + */ + maxlength: string; + + /** + * Current OTP value. + */ + value?: string; + + /** + * Disable the input. + */ + disabled?: boolean; +} + +/** + * Events emitted by + */ +interface FlutterShadcnInputOtpEvents { + /** Fired when the OTP value changes. */ + change: Event; + /** Fired when all slots are filled. */ + complete: Event; +} + +/** + * Properties for + * + * Groups OTP slots together visually. + */ +interface FlutterShadcnInputOtpGroupProperties {} + +interface FlutterShadcnInputOtpGroupEvents {} + +/** + * Properties for + * + * Individual character slot managed by the parent input. + */ +interface FlutterShadcnInputOtpSlotProperties {} + +interface FlutterShadcnInputOtpSlotEvents {} + +/** + * Properties for + * + * Visual separator between OTP groups. + */ +interface FlutterShadcnInputOtpSeparatorProperties {} + +interface FlutterShadcnInputOtpSeparatorEvents {} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input_otp.dart b/native_uis/webf_shadcn_ui/lib/src/components/input_otp.dart new file mode 100644 index 0000000000..ae27c778ef --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/input_otp.dart @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ + +import 'package:flutter/material.dart'; +import 'package:shadcn_ui/shadcn_ui.dart'; +import 'package:webf/webf.dart'; + +import 'input_otp_bindings_generated.dart'; + +/// WebF custom element that wraps shadcn_ui [ShadInputOTP]. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnInputOtp extends FlutterShadcnInputOtpBindings { + FlutterShadcnInputOtp(super.context); + + String _maxlength = ''; + String? _value; + bool _disabled = false; + + @override + String get maxlength => _maxlength; + + @override + set maxlength(value) { + final String v = value?.toString() ?? ''; + if (v != _maxlength) { + _maxlength = v; + state?.requestUpdateState(() {}); + } + } + + @override + String? get value => _value; + + @override + set value(value) { + final String? v = value?.toString(); + if (v != _value) { + _value = v; + state?.requestUpdateState(() {}); + } + } + + @override + bool get disabled => _disabled; + + @override + set disabled(value) { + final bool v = value == true || value == 'true' || value == ''; + if (v != _disabled) { + _disabled = v; + state?.requestUpdateState(() {}); + } + } + + int get maxLength => int.tryParse(_maxlength) ?? 6; + + @override + WebFWidgetElementState createState() => FlutterShadcnInputOtpState(this); +} + +class FlutterShadcnInputOtpState extends WebFWidgetElementState { + FlutterShadcnInputOtpState(super.widgetElement); + + @override + FlutterShadcnInputOtp get widgetElement => + super.widgetElement as FlutterShadcnInputOtp; + + List _buildChildren() { + final List children = []; + + for (final child in widgetElement.childNodes) { + if (child is FlutterShadcnInputOtpGroup) { + final slotCount = + child.childNodes.whereType().length; + children.add( + ShadInputOTPGroup( + children: List.generate(slotCount, (_) => const ShadInputOTPSlot()), + ), + ); + } else if (child is FlutterShadcnInputOtpSeparator) { + children.add(const Icon(Icons.remove, size: 16)); + } + } + + return children; + } + + @override + Widget build(BuildContext context) { + return ShadInputOTP( + maxLength: widgetElement.maxLength, + enabled: !widgetElement.disabled, + initialValue: widgetElement._value, + onChanged: (value) { + widgetElement._value = value; + widgetElement.dispatchEvent(Event('change')); + if (value.length == widgetElement.maxLength) { + widgetElement.dispatchEvent(Event('complete')); + } + }, + children: _buildChildren(), + ); + } +} + +/// WebF custom element for grouping OTP slots. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnInputOtpGroup extends WidgetElement { + FlutterShadcnInputOtpGroup(super.context); + + void _notifyParent() { + final parent = parentNode; + if (parent is FlutterShadcnInputOtp) { + parent.state?.requestUpdateState(() {}); + } + } + + @override + void connectedCallback() { + super.connectedCallback(); + _notifyParent(); + } + + @override + WebFWidgetElementState createState() => + FlutterShadcnInputOtpGroupState(this); +} + +class FlutterShadcnInputOtpGroupState extends WebFWidgetElementState { + FlutterShadcnInputOtpGroupState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +/// WebF custom element for individual OTP character slots. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnInputOtpSlot extends WidgetElement { + FlutterShadcnInputOtpSlot(super.context); + + void _notifyParent() { + final group = parentNode; + if (group is FlutterShadcnInputOtpGroup) { + group._notifyParent(); + } + } + + @override + void connectedCallback() { + super.connectedCallback(); + _notifyParent(); + } + + @override + WebFWidgetElementState createState() => + FlutterShadcnInputOtpSlotState(this); +} + +class FlutterShadcnInputOtpSlotState extends WebFWidgetElementState { + FlutterShadcnInputOtpSlotState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +/// WebF custom element for visual separator between OTP groups. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnInputOtpSeparator extends WidgetElement { + FlutterShadcnInputOtpSeparator(super.context); + + void _notifyParent() { + final parent = parentNode; + if (parent is FlutterShadcnInputOtp) { + parent.state?.requestUpdateState(() {}); + } + } + + @override + void connectedCallback() { + super.connectedCallback(); + _notifyParent(); + } + + @override + WebFWidgetElementState createState() => + FlutterShadcnInputOtpSeparatorState(this); +} + +class FlutterShadcnInputOtpSeparatorState extends WebFWidgetElementState { + FlutterShadcnInputOtpSeparatorState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/input_otp_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/input_otp_bindings_generated.dart new file mode 100644 index 0000000000..0dcf6546b1 --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/input_otp_bindings_generated.dart @@ -0,0 +1,60 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `webf codegen` +// ignore_for_file: avoid_unused_constructor_parameters +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: implementation_imports +// ignore_for_file: library_private_types_in_public_api +// ignore_for_file: prefer_void_to_null +import 'package:webf/webf.dart'; +abstract class FlutterShadcnInputOtpBindings extends WidgetElement { + FlutterShadcnInputOtpBindings(super.context); + String get maxlength; + set maxlength(value); + String? get value; + set value(value); + bool get disabled; + set disabled(value); + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['maxlength'] = ElementAttributeProperty( + getter: () => maxlength.toString(), + setter: (value) => maxlength = value, + deleter: () => maxlength = '' + ); + attributes['value'] = ElementAttributeProperty( + getter: () => value?.toString(), + setter: (value) => value = value, + deleter: () => value = null + ); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (value) => disabled = value == 'true' || value == '', + deleter: () => disabled = false + ); + } + static StaticDefinedBindingPropertyMap flutterShadcnInputOtpProperties = { + 'maxlength': StaticDefinedBindingProperty( + getter: (element) => castToType(element).maxlength, + setter: (element, value) => + castToType(element).maxlength = value, + ), + 'value': StaticDefinedBindingProperty( + getter: (element) => castToType(element).value, + setter: (element, value) => + castToType(element).value = value, + ), + 'disabled': StaticDefinedBindingProperty( + getter: (element) => castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = value, + ), + }; + @override + List get properties => [ + ...super.properties, + flutterShadcnInputOtpProperties, + ]; +} \ No newline at end of file diff --git a/native_uis/webf_shadcn_ui/lib/src/components/menubar.dart b/native_uis/webf_shadcn_ui/lib/src/components/menubar.dart new file mode 100644 index 0000000000..132cc4430b --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/menubar.dart @@ -0,0 +1,1242 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ + +import 'dart:async'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shadcn_ui/shadcn_ui.dart'; +import 'package:webf/css.dart'; +import 'package:webf/webf.dart'; + +const Map _menubarDefaultStyle = { + DISPLAY: INLINE_FLEX, +}; + +/// Helper to extract text content from nodes recursively. +String _extractTextContent(Iterable nodes) { + final buffer = StringBuffer(); + for (final node in nodes) { + if (node is TextNode) { + buffer.write(node.data); + } else if (node.childNodes.isNotEmpty) { + buffer.write(_extractTextContent(node.childNodes)); + } + } + return buffer.toString().trim(); +} + +class _ParsedShortcut { + const _ParsedShortcut({ + required this.meta, + required this.control, + required this.alt, + required this.shift, + this.logicalKey, + this.keyLabel, + }); + + final bool meta; + final bool control; + final bool alt; + final bool shift; + final LogicalKeyboardKey? logicalKey; + final String? keyLabel; + + bool matches(KeyDownEvent event) { + final keyboard = HardwareKeyboard.instance; + if (keyboard.isMetaPressed != meta) return false; + if (keyboard.isControlPressed != control) return false; + if (keyboard.isAltPressed != alt) return false; + if (keyboard.isShiftPressed != shift) return false; + if (logicalKey != null) return event.logicalKey == logicalKey; + final expectedLabel = keyLabel?.toUpperCase().trim(); + if (expectedLabel == null || expectedLabel.isEmpty) return false; + return event.logicalKey.keyLabel.toUpperCase().trim() == expectedLabel; + } +} + +_ParsedShortcut? _parseShortcut(String? rawShortcut) { + var shortcut = rawShortcut?.trim(); + if (shortcut == null || shortcut.isEmpty) return null; + + var meta = false; + var control = false; + var alt = false; + var shift = false; + String? keyToken; + + if (shortcut.contains('+')) { + final parts = shortcut + .split('+') + .map((p) => p.trim()) + .where((p) => p.isNotEmpty); + for (final part in parts) { + final normalized = part.toLowerCase(); + if (normalized == 'cmd' || + normalized == 'command' || + normalized == 'meta' || + normalized == 'win' || + normalized == 'super') { + meta = true; + } else if (normalized == 'ctrl' || normalized == 'control') { + control = true; + } else if (normalized == 'alt' || normalized == 'option') { + alt = true; + } else if (normalized == 'shift') { + shift = true; + } else { + keyToken = part; + } + } + } else { + if (shortcut.contains('⌘')) { + meta = true; + shortcut = shortcut.replaceAll('⌘', ''); + } + if (shortcut.contains('⌃')) { + control = true; + shortcut = shortcut.replaceAll('⌃', ''); + } + if (shortcut.contains('⌥')) { + alt = true; + shortcut = shortcut.replaceAll('⌥', ''); + } + if (shortcut.contains('⇧')) { + shift = true; + shortcut = shortcut.replaceAll('⇧', ''); + } + keyToken = shortcut.trim(); + } + + final isApplePlatform = defaultTargetPlatform == TargetPlatform.macOS || + defaultTargetPlatform == TargetPlatform.iOS; + if (meta && !isApplePlatform) { + meta = false; + control = true; + } + + final key = keyToken?.trim(); + if (key == null || key.isEmpty) return null; + + final normalizedKey = key.toUpperCase(); + final LogicalKeyboardKey? logicalKey = switch (normalizedKey) { + '⌫' || 'BACKSPACE' => LogicalKeyboardKey.backspace, + 'DEL' || 'DELETE' => LogicalKeyboardKey.delete, + 'ESC' || 'ESCAPE' => LogicalKeyboardKey.escape, + 'ENTER' || 'RETURN' || '⏎' => LogicalKeyboardKey.enter, + 'TAB' => LogicalKeyboardKey.tab, + 'SPACE' || '␣' => LogicalKeyboardKey.space, + _ => null, + }; + + return _ParsedShortcut( + meta: meta, + control: control, + alt: alt, + shift: shift, + logicalKey: logicalKey, + keyLabel: logicalKey == null ? normalizedKey : null, + ); +} + +class _ShortcutBinding { + const _ShortcutBinding(this.shortcut, this.item); + final _ParsedShortcut shortcut; + final FlutterShadcnMenubarItem item; +} + +class _MenubarSubmenuTrigger extends StatefulWidget { + const _MenubarSubmenuTrigger({ + super.key, + required this.label, + required this.items, + required this.inset, + required this.enabled, + required this.isNestedSubmenu, + }); + + final String label; + final List items; + final bool inset; + final bool enabled; + final bool isNestedSubmenu; + + @override + State<_MenubarSubmenuTrigger> createState() => _MenubarSubmenuTriggerState(); +} + +class _MenubarSubmenuTriggerState extends State<_MenubarSubmenuTrigger> { + final ShadContextMenuController _controller = ShadContextMenuController(); + final Object _groupId = Object(); + bool _insideTrigger = false; + bool _insidePopover = false; + Timer? _closeTimer; + + @override + void dispose() { + _closeTimer?.cancel(); + _controller.dispose(); + super.dispose(); + } + + void _scheduleCloseIfNeeded() { + _closeTimer?.cancel(); + if (!_controller.isOpen) return; + if (_insideTrigger || _insidePopover) return; + _closeTimer = Timer(const Duration(milliseconds: 80), () { + if (!mounted) return; + if (_insideTrigger || _insidePopover) return; + _controller.hide(); + }); + } + + void _onTriggerHoverChanged(bool inside) { + _insideTrigger = inside; + if (!widget.enabled) return; + if (inside) { + _controller.show(); + } else { + _scheduleCloseIfNeeded(); + } + } + + void _onPopoverHoverChanged(bool inside) { + _insidePopover = inside; + if (!widget.enabled) return; + if (inside) { + _controller.show(); + } else { + _scheduleCloseIfNeeded(); + } + } + + void _toggleOpen() { + if (!widget.enabled) return; + if (_controller.isOpen) { + _controller.hide(); + } else { + _controller.show(); + } + } + + @override + Widget build(BuildContext context) { + final theme = ShadTheme.of(context); + + final effectiveItemPadding = theme.contextMenuTheme.itemPadding ?? + const EdgeInsets.symmetric(horizontal: 4); + + final defaultInsetPadding = widget.inset + ? const EdgeInsetsDirectional.only(start: 32, end: 8) + : const EdgeInsets.symmetric(horizontal: 8); + + final effectiveInsetPadding = + theme.contextMenuTheme.insetPadding ?? defaultInsetPadding; + + final effectiveTrailingPadding = theme.contextMenuTheme.trailingPadding ?? + const EdgeInsetsDirectional.only(start: 8); + + final effectiveHeight = theme.contextMenuTheme.height ?? 32; + + final effectiveButtonVariant = + theme.contextMenuTheme.buttonVariant ?? ShadButtonVariant.ghost; + + final effectiveDecoration = const ShadDecoration( + secondaryBorder: ShadBorder.none, + secondaryFocusedBorder: ShadBorder.none, + ).merge(theme.contextMenuTheme.itemDecoration); + + final effectiveTextStyle = + (theme.contextMenuTheme.textStyle ?? + theme.textTheme.small.copyWith(fontWeight: FontWeight.normal)) + .fallback(color: theme.colorScheme.foreground); + + final effectiveSelectedBackgroundColor = + theme.contextMenuTheme.selectedBackgroundColor ?? theme.colorScheme.accent; + final effectiveBackgroundColor = theme.contextMenuTheme.backgroundColor; + + final effectiveAnchor = theme.contextMenuTheme.anchor ?? + ShadAnchorAuto( + offset: Offset(-8, widget.isNestedSubmenu ? -5 : -3), + targetAnchor: Alignment.topRight, + followerAnchor: Alignment.bottomRight, + ); + + final popoverContent = MouseRegion( + onEnter: (_) => _onPopoverHoverChanged(true), + onExit: (_) => _onPopoverHoverChanged(false), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: widget.items, + ), + ); + + return ListenableBuilder( + listenable: _controller, + builder: (context, _) { + final selected = _insideTrigger || _insidePopover || _controller.isOpen; + return ShadContextMenu( + controller: _controller, + anchor: effectiveAnchor, + groupId: _groupId, + onHoverArea: (hovered) => + hovered ? _onTriggerHoverChanged(true) : _onTriggerHoverChanged(false), + items: [popoverContent], + child: MouseRegion( + onEnter: (_) => _onTriggerHoverChanged(true), + onExit: (_) => _onTriggerHoverChanged(false), + child: Padding( + padding: effectiveItemPadding, + child: ShadButton.raw( + height: effectiveHeight, + enabled: widget.enabled, + variant: effectiveButtonVariant, + decoration: effectiveDecoration, + width: double.infinity, + padding: effectiveInsetPadding, + backgroundColor: selected + ? effectiveSelectedBackgroundColor + : effectiveBackgroundColor, + hoverBackgroundColor: effectiveSelectedBackgroundColor, + onPressed: _toggleOpen, + child: Expanded( + child: Row( + children: [ + Expanded( + child: DefaultTextStyle( + style: effectiveTextStyle, + child: Text( + widget.label, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + ), + ), + Padding( + padding: effectiveTrailingPadding, + child: const Icon(LucideIcons.chevronRight, size: 16), + ), + ], + ), + ), + ), + ), + ), + ); + }, + ); + } +} + +// --------------------------------------------------------------------------- +// Main Menubar element +// --------------------------------------------------------------------------- + +/// WebF custom element for the menubar container. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnMenubar extends WidgetElement { + FlutterShadcnMenubar(super.context); + + @override + Map get defaultStyle => _menubarDefaultStyle; + + @override + WebFWidgetElementState createState() => FlutterShadcnMenubarState(this); +} + +class FlutterShadcnMenubarState extends WebFWidgetElementState { + FlutterShadcnMenubarState(super.widgetElement); + + @override + FlutterShadcnMenubar get widgetElement => + super.widgetElement as FlutterShadcnMenubar; + + List _buildMenuItems( + Iterable nodes, + List<_ShortcutBinding> shortcutBindings, { + String? radioGroupValue, + FlutterShadcnMenubarRadioGroup? radioGroup, + bool isSubMenu = false, + }) { + final items = []; + for (final node in nodes) { + if (node is FlutterShadcnMenubarItem) { + final text = _extractTextContent(node.childNodes); + final shortcut = node.shortcut ?? node.getAttribute('shortcut'); + final isInset = node.inset || + node.getAttribute('inset') == 'true' || + node.getAttribute('inset') == ''; + + Widget? trailingWidget; + if (shortcut != null && shortcut.isNotEmpty) { + trailingWidget = Text(shortcut); + } + + final parsedShortcut = _parseShortcut(shortcut); + if (parsedShortcut != null) { + shortcutBindings.add(_ShortcutBinding(parsedShortcut, node)); + } + + if (isInset) { + items.add( + ShadContextMenuItem.inset( + enabled: !node.disabled, + trailing: trailingWidget, + onPressed: () { + node.dispatchEvent(Event('click')); + }, + child: Text(text), + ), + ); + } else { + items.add( + ShadContextMenuItem( + enabled: !node.disabled, + trailing: trailingWidget, + onPressed: () { + node.dispatchEvent(Event('click')); + }, + child: Text(text), + ), + ); + } + } else if (node is FlutterShadcnMenubarSeparator) { + items.add(const ShadSeparator.horizontal( + margin: EdgeInsets.symmetric(vertical: 4), + )); + } else if (node is FlutterShadcnMenubarLabel) { + final text = _extractTextContent(node.childNodes); + items.add( + Padding( + padding: const EdgeInsets.fromLTRB(36, 8, 8, 8), + child: Builder( + builder: (context) { + final theme = ShadTheme.of(context); + return Text(text, style: theme.textTheme.small); + }, + ), + ), + ); + } else if (node is FlutterShadcnMenubarSub) { + FlutterShadcnMenubarSubTrigger? trigger; + FlutterShadcnMenubarSubContent? subContent; + + for (final child in node.childNodes) { + if (child is FlutterShadcnMenubarSubTrigger) { + trigger = child; + } else if (child is FlutterShadcnMenubarSubContent) { + subContent = child; + } + } + + if (trigger != null) { + final text = _extractTextContent(trigger.childNodes); + final isInset = trigger.inset || + trigger.getAttribute('inset') == 'true' || + trigger.getAttribute('inset') == ''; + final subItems = subContent != null + ? _buildMenuItems( + subContent.childNodes, + shortcutBindings, + isSubMenu: true, + ) + : []; + + items.add( + _MenubarSubmenuTrigger( + key: ObjectKey(node), + label: text, + inset: isInset, + enabled: !trigger.disabled, + isNestedSubmenu: isSubMenu, + items: subItems, + ), + ); + } + } else if (node is FlutterShadcnMenubarCheckboxItem) { + final text = _extractTextContent(node.childNodes); + final shortcut = node.shortcut ?? node.getAttribute('shortcut'); + + Widget? trailingWidget; + if (shortcut != null && shortcut.isNotEmpty) { + trailingWidget = Text(shortcut); + } + + items.add( + ShadContextMenuItem( + enabled: !node.disabled, + leading: node.checked + ? const Icon(LucideIcons.check, size: 16) + : const SizedBox(width: 16), + trailing: trailingWidget, + onPressed: () { + node._checked = !node._checked; + node.dispatchEvent(Event('change')); + node._notifyMenuNeedsRebuild(); + }, + child: Text(text), + ), + ); + } else if (node is FlutterShadcnMenubarRadioGroup) { + final groupItems = _buildMenuItems( + node.childNodes, + shortcutBindings, + radioGroupValue: node.value, + radioGroup: node, + isSubMenu: isSubMenu, + ); + items.addAll(groupItems); + } else if (node is FlutterShadcnMenubarRadioItem) { + final text = _extractTextContent(node.childNodes); + final shortcut = node.shortcut ?? node.getAttribute('shortcut'); + final isSelected = + radioGroupValue != null && node.value == radioGroupValue; + + Widget? trailingWidget; + if (shortcut != null && shortcut.isNotEmpty) { + trailingWidget = Text(shortcut); + } + + items.add( + ShadContextMenuItem( + enabled: !node.disabled, + leading: isSelected + ? SizedBox.square( + dimension: 16, + child: Center( + child: Container( + width: 8, + height: 8, + decoration: const BoxDecoration( + color: Colors.black, + shape: BoxShape.circle, + ), + ), + ), + ) + : const SizedBox(width: 16), + trailing: trailingWidget, + onPressed: () { + if (radioGroup != null && node.value != null) { + radioGroup._value = node.value; + radioGroup.dispatchEvent( + CustomEvent('change', detail: {'value': node.value})); + radioGroup._notifyMenuNeedsRebuild(); + } + node.dispatchEvent(Event('click')); + }, + child: Text(text), + ), + ); + } + } + return items; + } + + @override + Widget build(BuildContext context) { + final menuWidgets = []; + + for (final child in widgetElement.childNodes) { + if (child is FlutterShadcnMenubarMenu) { + FlutterShadcnMenubarTrigger? trigger; + FlutterShadcnMenubarContent? content; + + for (final menuChild in child.childNodes) { + if (menuChild is FlutterShadcnMenubarTrigger) { + trigger = menuChild; + } else if (menuChild is FlutterShadcnMenubarContent) { + content = menuChild; + } + } + + if (trigger != null) { + final triggerText = _extractTextContent(trigger.childNodes); + final shortcutBindings = <_ShortcutBinding>[]; + final items = content != null + ? _buildMenuItems(content.childNodes, shortcutBindings) + : []; + + menuWidgets.add( + ShadMenubarItem( + items: items, + child: Text(triggerText), + ), + ); + } + } + } + + return ShadMenubar(items: menuWidgets); + } +} + +// --------------------------------------------------------------------------- +// Menubar Menu (groups trigger + content) +// --------------------------------------------------------------------------- + +/// WebF custom element for a single menu in the menubar. +class FlutterShadcnMenubarMenu extends WidgetElement { + FlutterShadcnMenubarMenu(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarMenuState(this); +} + +class FlutterShadcnMenubarMenuState extends WebFWidgetElementState { + FlutterShadcnMenubarMenuState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Trigger +// --------------------------------------------------------------------------- + +/// WebF custom element for the menubar trigger label. +class FlutterShadcnMenubarTrigger extends WidgetElement { + FlutterShadcnMenubarTrigger(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarTriggerState(this); +} + +class FlutterShadcnMenubarTriggerState extends WebFWidgetElementState { + FlutterShadcnMenubarTriggerState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Content +// --------------------------------------------------------------------------- + +/// WebF custom element for the menubar dropdown content. +class FlutterShadcnMenubarContent extends WidgetElement { + FlutterShadcnMenubarContent(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarContentState(this); +} + +class FlutterShadcnMenubarContentState extends WebFWidgetElementState { + FlutterShadcnMenubarContentState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Item +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar menu item. +class FlutterShadcnMenubarItem extends WidgetElement { + FlutterShadcnMenubarItem(super.context); + + bool _disabled = false; + String? _shortcut; + bool _inset = false; + + void _notifyMenuNeedsRebuild() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnMenubar) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + bool get disabled => _disabled; + + set disabled(value) { + final bool v = value == true; + if (v != _disabled) { + _disabled = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + String? get shortcut => _shortcut; + + set shortcut(value) { + final String? v = value?.toString(); + if (v != _shortcut) { + _shortcut = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + bool get inset => _inset; + + set inset(value) { + final bool v = value == true; + if (v != _inset) { + _inset = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (val) => disabled = val == 'true' || val == '', + deleter: () => disabled = false); + attributes['shortcut'] = ElementAttributeProperty( + getter: () => shortcut, + setter: (val) => shortcut = val, + deleter: () => shortcut = null); + attributes['inset'] = ElementAttributeProperty( + getter: () => inset.toString(), + setter: (val) => inset = val == 'true' || val == '', + deleter: () => inset = false); + } + + static StaticDefinedBindingPropertyMap + flutterShadcnMenubarItemProperties = { + 'disabled': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = value, + ), + 'shortcut': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).shortcut, + setter: (element, value) => + castToType(element).shortcut = value, + ), + 'inset': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).inset, + setter: (element, value) => + castToType(element).inset = value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnMenubarItemProperties, + ]; + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarItemState(this); +} + +class FlutterShadcnMenubarItemState extends WebFWidgetElementState { + FlutterShadcnMenubarItemState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Separator +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar separator. +class FlutterShadcnMenubarSeparator extends WidgetElement { + FlutterShadcnMenubarSeparator(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarSeparatorState(this); +} + +class FlutterShadcnMenubarSeparatorState extends WebFWidgetElementState { + FlutterShadcnMenubarSeparatorState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Label +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar label (group header). +class FlutterShadcnMenubarLabel extends WidgetElement { + FlutterShadcnMenubarLabel(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarLabelState(this); +} + +class FlutterShadcnMenubarLabelState extends WebFWidgetElementState { + FlutterShadcnMenubarLabelState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Sub (submenu container) +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar sub-menu. +class FlutterShadcnMenubarSub extends WidgetElement { + FlutterShadcnMenubarSub(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarSubState(this); +} + +class FlutterShadcnMenubarSubState extends WebFWidgetElementState { + FlutterShadcnMenubarSubState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Sub Trigger +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar sub-menu trigger. +class FlutterShadcnMenubarSubTrigger extends WidgetElement { + FlutterShadcnMenubarSubTrigger(super.context); + + bool _disabled = false; + bool _inset = false; + + bool get disabled => _disabled; + + set disabled(value) { + final bool v = value == true; + if (v != _disabled) { + _disabled = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + bool get inset => _inset; + + set inset(value) { + final bool v = value == true; + if (v != _inset) { + _inset = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + void _notifyMenuNeedsRebuild() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnMenubar) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (val) => disabled = val == 'true' || val == '', + deleter: () => disabled = false); + attributes['inset'] = ElementAttributeProperty( + getter: () => inset.toString(), + setter: (val) => inset = val == 'true' || val == '', + deleter: () => inset = false); + } + + static StaticDefinedBindingPropertyMap + flutterShadcnMenubarSubTriggerProperties = { + 'disabled': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = value, + ), + 'inset': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).inset, + setter: (element, value) => + castToType(element).inset = value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnMenubarSubTriggerProperties, + ]; + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarSubTriggerState(this); +} + +class FlutterShadcnMenubarSubTriggerState extends WebFWidgetElementState { + FlutterShadcnMenubarSubTriggerState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Sub Content +// --------------------------------------------------------------------------- + +/// WebF custom element for menubar sub-menu content. +class FlutterShadcnMenubarSubContent extends WidgetElement { + FlutterShadcnMenubarSubContent(super.context); + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarSubContentState(this); +} + +class FlutterShadcnMenubarSubContentState extends WebFWidgetElementState { + FlutterShadcnMenubarSubContentState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Checkbox Item +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar checkbox item. +class FlutterShadcnMenubarCheckboxItem extends WidgetElement { + FlutterShadcnMenubarCheckboxItem(super.context); + + bool _disabled = false; + bool _checked = false; + String? _shortcut; + + void _notifyMenuNeedsRebuild() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnMenubar) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + bool get disabled => _disabled; + + set disabled(value) { + final bool v = value == true; + if (v != _disabled) { + _disabled = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + bool get checked => _checked; + + set checked(value) { + final bool v = value == true; + if (v != _checked) { + _checked = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + String? get shortcut => _shortcut; + + set shortcut(value) { + final String? v = value?.toString(); + if (v != _shortcut) { + _shortcut = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (val) => disabled = val == 'true' || val == '', + deleter: () => disabled = false); + attributes['checked'] = ElementAttributeProperty( + getter: () => checked.toString(), + setter: (val) => checked = val == 'true' || val == '', + deleter: () => checked = false); + attributes['shortcut'] = ElementAttributeProperty( + getter: () => shortcut, + setter: (val) => shortcut = val, + deleter: () => shortcut = null); + } + + static StaticDefinedBindingPropertyMap + flutterShadcnMenubarCheckboxItemProperties = { + 'disabled': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = + value, + ), + 'checked': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).checked, + setter: (element, value) => + castToType(element).checked = value, + ), + 'shortcut': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).shortcut, + setter: (element, value) => + castToType(element).shortcut = + value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnMenubarCheckboxItemProperties, + ]; + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarCheckboxItemState(this); +} + +class FlutterShadcnMenubarCheckboxItemState extends WebFWidgetElementState { + FlutterShadcnMenubarCheckboxItemState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Radio Group +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar radio group. +class FlutterShadcnMenubarRadioGroup extends WidgetElement { + FlutterShadcnMenubarRadioGroup(super.context); + + String? _value; + + void _notifyMenuNeedsRebuild() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnMenubar) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + String? get value => _value; + + set value(val) { + final String? v = val?.toString(); + if (v != _value) { + _value = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['value'] = ElementAttributeProperty( + getter: () => value, + setter: (val) => value = val, + deleter: () => value = null); + } + + static StaticDefinedBindingPropertyMap + flutterShadcnMenubarRadioGroupProperties = { + 'value': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).value, + setter: (element, value) => + castToType(element).value = value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnMenubarRadioGroupProperties, + ]; + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarRadioGroupState(this); +} + +class FlutterShadcnMenubarRadioGroupState extends WebFWidgetElementState { + FlutterShadcnMenubarRadioGroupState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + +// --------------------------------------------------------------------------- +// Menubar Radio Item +// --------------------------------------------------------------------------- + +/// WebF custom element for a menubar radio item. +class FlutterShadcnMenubarRadioItem extends WidgetElement { + FlutterShadcnMenubarRadioItem(super.context); + + bool _disabled = false; + String? _value; + String? _shortcut; + + void _notifyMenuNeedsRebuild() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnMenubar) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + bool get disabled => _disabled; + + set disabled(value) { + final bool v = value == true; + if (v != _disabled) { + _disabled = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + String? get value => _value; + + set value(val) { + final String? v = val?.toString(); + if (v != _value) { + _value = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + String? get shortcut => _shortcut; + + set shortcut(value) { + final String? v = value?.toString(); + if (v != _shortcut) { + _shortcut = v; + _notifyMenuNeedsRebuild(); + state?.requestUpdateState(() {}); + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (val) => disabled = val == 'true' || val == '', + deleter: () => disabled = false); + attributes['value'] = ElementAttributeProperty( + getter: () => value, + setter: (val) => value = val, + deleter: () => value = null); + attributes['shortcut'] = ElementAttributeProperty( + getter: () => shortcut, + setter: (val) => shortcut = val, + deleter: () => shortcut = null); + } + + static StaticDefinedBindingPropertyMap + flutterShadcnMenubarRadioItemProperties = { + 'disabled': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).disabled, + setter: (element, value) => + castToType(element).disabled = value, + ), + 'value': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).value, + setter: (element, value) => + castToType(element).value = value, + ), + 'shortcut': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).shortcut, + setter: (element, value) => + castToType(element).shortcut = value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnMenubarRadioItemProperties, + ]; + + @override + WebFWidgetElementState createState() => + FlutterShadcnMenubarRadioItemState(this); +} + +class FlutterShadcnMenubarRadioItemState extends WebFWidgetElementState { + FlutterShadcnMenubarRadioItemState(super.widgetElement); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/popover.dart b/native_uis/webf_shadcn_ui/lib/src/components/popover.dart index 8c0c5efeb7..bb45fa9a66 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/popover.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/popover.dart @@ -11,6 +11,111 @@ import 'package:webf/webf.dart'; import 'popover_bindings_generated.dart'; +/// Converts a placement string (e.g. 'top', 'bottom-start') to a +/// [ShadAnchorAuto] anchor for the popover. +ShadAnchorBase _placementToAnchor(String placement, String align) { + // Parse combined placement like "top-start", "bottom-end" + String side = placement; + String resolvedAlign = align; + if (placement.contains('-')) { + final parts = placement.split('-'); + side = parts[0]; + if (resolvedAlign == 'center') { + resolvedAlign = parts[1]; + } + } + + switch (side) { + case 'top': + return ShadAnchorAuto( + offset: const Offset(0, -4), + followerAnchor: _alignToFollower('top', resolvedAlign), + targetAnchor: _alignToTarget('top', resolvedAlign), + ); + case 'left': + return ShadAnchorAuto( + offset: const Offset(-4, 0), + followerAnchor: _alignToFollower('left', resolvedAlign), + targetAnchor: _alignToTarget('left', resolvedAlign), + ); + case 'right': + return ShadAnchorAuto( + offset: const Offset(4, 0), + followerAnchor: _alignToFollower('right', resolvedAlign), + targetAnchor: _alignToTarget('right', resolvedAlign), + ); + case 'bottom': + default: + return ShadAnchorAuto( + offset: const Offset(0, 4), + followerAnchor: _alignToFollower('bottom', resolvedAlign), + targetAnchor: _alignToTarget('bottom', resolvedAlign), + ); + } +} + +Alignment _alignToFollower(String side, String align) { + switch (side) { + case 'top': + return switch (align) { + 'start' => Alignment.topLeft, + 'end' => Alignment.topRight, + _ => Alignment.topCenter, + }; + case 'bottom': + return switch (align) { + 'start' => Alignment.bottomLeft, + 'end' => Alignment.bottomRight, + _ => Alignment.bottomCenter, + }; + case 'left': + return switch (align) { + 'start' => Alignment.topLeft, + 'end' => Alignment.bottomLeft, + _ => Alignment.centerLeft, + }; + case 'right': + return switch (align) { + 'start' => Alignment.topRight, + 'end' => Alignment.bottomRight, + _ => Alignment.centerRight, + }; + default: + return Alignment.bottomCenter; + } +} + +Alignment _alignToTarget(String side, String align) { + switch (side) { + case 'top': + return switch (align) { + 'start' => Alignment.topLeft, + 'end' => Alignment.topRight, + _ => Alignment.topCenter, + }; + case 'bottom': + return switch (align) { + 'start' => Alignment.bottomLeft, + 'end' => Alignment.bottomRight, + _ => Alignment.bottomCenter, + }; + case 'left': + return switch (align) { + 'start' => Alignment.topLeft, + 'end' => Alignment.bottomLeft, + _ => Alignment.centerLeft, + }; + case 'right': + return switch (align) { + 'start' => Alignment.topRight, + 'end' => Alignment.bottomRight, + _ => Alignment.centerRight, + }; + default: + return Alignment.bottomCenter; + } +} + /// WebF custom element that wraps shadcn_ui [ShadPopover]. /// /// Exposed as `` in the DOM. @@ -19,6 +124,7 @@ class FlutterShadcnPopover extends FlutterShadcnPopoverBindings { bool _open = false; String _placement = 'bottom'; + String _align = 'center'; bool _closeOnOutsideClick = true; @override @@ -50,6 +156,16 @@ class FlutterShadcnPopover extends FlutterShadcnPopoverBindings { } } + String get align => _align; + + set align(value) { + final String newValue = value?.toString() ?? 'center'; + if (newValue != _align) { + _align = newValue; + state?.requestUpdateState(() {}); + } + } + @override bool get closeOnOutsideClick => _closeOnOutsideClick; @@ -58,9 +174,35 @@ class FlutterShadcnPopover extends FlutterShadcnPopoverBindings { final bool v = value == true; if (v != _closeOnOutsideClick) { _closeOnOutsideClick = v; + state?.requestUpdateState(() {}); } } + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['align'] = ElementAttributeProperty( + getter: () => align, + setter: (val) => align = val, + deleter: () => align = 'center', + ); + } + + static StaticDefinedBindingPropertyMap flutterShadcnPopoverExtraProperties = { + 'align': StaticDefinedBindingProperty( + getter: (element) => + castToType(element).align, + setter: (element, value) => + castToType(element).align = value, + ), + }; + + @override + List get properties => [ + ...super.properties, + flutterShadcnPopoverExtraProperties, + ]; + @override WebFWidgetElementState createState() => FlutterShadcnPopoverState(this); } @@ -69,13 +211,29 @@ class FlutterShadcnPopoverState extends WebFWidgetElementState { FlutterShadcnPopoverState(super.widgetElement); final _popoverController = ShadPopoverController(); + Offset? _tapDownPosition; @override FlutterShadcnPopover get widgetElement => super.widgetElement as FlutterShadcnPopover; + void _onControllerChanged() { + final isOpen = _popoverController.isOpen; + // Sync native open/close state back to JS and emit events. + if (widgetElement.open != isOpen) { + widgetElement.open = isOpen; + } + } + + @override + void initState() { + super.initState(); + _popoverController.addListener(_onControllerChanged); + } + @override void dispose() { + _popoverController.removeListener(_onControllerChanged); _popoverController.dispose(); super.dispose(); } @@ -101,20 +259,43 @@ class FlutterShadcnPopoverState extends WebFWidgetElementState { // Sync controller with open state if (widgetElement.open && !_popoverController.isOpen) { WidgetsBinding.instance.addPostFrameCallback((_) { - _popoverController.show(); + if (mounted) _popoverController.show(); }); } else if (!widgetElement.open && _popoverController.isOpen) { WidgetsBinding.instance.addPostFrameCallback((_) { - _popoverController.hide(); + if (mounted) _popoverController.hide(); }); } + final anchor = _placementToAnchor( + widgetElement.placement, + widgetElement.align, + ); + return ShadPopover( controller: _popoverController, + anchor: anchor, + closeOnTapOutside: widgetElement.closeOnOutsideClick, popover: (context) => content ?? const SizedBox.shrink(), - child: GestureDetector( - onTap: () { - widgetElement.open = !widgetElement.open; + // Use Listener instead of GestureDetector to avoid gesture arena + // conflicts with interactive child widgets (e.g. ShadButton). + // Listener receives raw pointer events without competing in the arena. + child: Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (event) { + _tapDownPosition = event.position; + }, + onPointerUp: (event) { + if (_tapDownPosition != null) { + final distance = (event.position - _tapDownPosition!).distance; + _tapDownPosition = null; + if (distance < 20) { + widgetElement.open = !widgetElement.open; + } + } + }, + onPointerCancel: (_) { + _tapDownPosition = null; }, child: trigger, ), @@ -171,7 +352,7 @@ class FlutterShadcnPopoverContentState extends WebFWidgetElementState { border: Border.all(color: theme.colorScheme.border), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.1), + color: Colors.black.withValues(alpha: 0.1), blurRadius: 10, ), ], diff --git a/native_uis/webf_shadcn_ui/lib/src/components/popover_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/popover_bindings_generated.dart index 1060bb8ecc..c7517f1f0f 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/popover_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/popover_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnPopoverBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); attributes['placement'] = ElementAttributeProperty( getter: () => placement?.toString(), - setter: (value) => this.placement = value, + setter: (value) => placement = value, deleter: () => placement = null ); attributes['close-on-outside-click'] = ElementAttributeProperty( getter: () => closeOnOutsideClick.toString(), - setter: (value) => this.closeOnOutsideClick = value == 'true' || value == '', + setter: (value) => closeOnOutsideClick = value == 'true' || value == '', deleter: () => closeOnOutsideClick = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/progress.d.ts b/native_uis/webf_shadcn_ui/lib/src/components/progress.d.ts index 09a6ffe671..9bd7197c53 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/progress.d.ts +++ b/native_uis/webf_shadcn_ui/lib/src/components/progress.d.ts @@ -31,6 +31,31 @@ interface FlutterShadcnProgressProperties { * Default: 'default' */ variant?: string; + + /** + * Background color of the progress track. + * Accepts hex color string (e.g. '#e0e0e0', '#FF808080'). + */ + backgroundColor?: string; + + /** + * Color of the progress indicator. + * Accepts hex color string (e.g. '#3b82f6', '#FF0000FF'). + */ + color?: string; + + /** + * Minimum height of the progress bar in logical pixels. + * Default: 16 + */ + minHeight?: string; + + /** + * Border radius of the progress bar in logical pixels. + * Applied uniformly to all corners. + * Default: 16 + */ + borderRadius?: string; } interface FlutterShadcnProgressEvents {} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/progress.dart b/native_uis/webf_shadcn_ui/lib/src/components/progress.dart index ad3850376a..4800b6f5ad 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/progress.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/progress.dart @@ -18,6 +18,10 @@ class FlutterShadcnProgress extends FlutterShadcnProgressBindings { double _value = 0; double _max = 100; String _variant = 'default'; + Color? _backgroundColor; + Color? _color; + double? _minHeight; + double? _borderRadius; @override String? get value => _value.toString(); @@ -58,6 +62,73 @@ class FlutterShadcnProgress extends FlutterShadcnProgressBindings { } } + @override + String? get backgroundColor => _backgroundColor != null + ? '#${_backgroundColor!.value.toRadixString(16).padLeft(8, '0')}' + : null; + + @override + set backgroundColor(value) { + final newValue = value != null ? _parseColor(value.toString()) : null; + if (newValue != _backgroundColor) { + _backgroundColor = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get color => _color != null + ? '#${_color!.value.toRadixString(16).padLeft(8, '0')}' + : null; + + @override + set color(value) { + final newValue = value != null ? _parseColor(value.toString()) : null; + if (newValue != _color) { + _color = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get minHeight => _minHeight?.toString(); + + @override + set minHeight(value) { + final newValue = value != null ? double.tryParse(value.toString()) : null; + if (newValue != _minHeight) { + _minHeight = newValue; + state?.requestUpdateState(() {}); + } + } + + @override + String? get borderRadius => _borderRadius?.toString(); + + @override + set borderRadius(value) { + final newValue = value != null ? double.tryParse(value.toString()) : null; + if (newValue != _borderRadius) { + _borderRadius = newValue; + state?.requestUpdateState(() {}); + } + } + + static Color? _parseColor(String value) { + final trimmed = value.trim().toLowerCase(); + if (trimmed.startsWith('#')) { + final hex = trimmed.substring(1); + if (hex.length == 6) { + final intValue = int.tryParse(hex, radix: 16); + if (intValue != null) return Color(0xFF000000 | intValue); + } else if (hex.length == 8) { + final intValue = int.tryParse(hex, radix: 16); + if (intValue != null) return Color(intValue); + } + } + return null; + } + @override WebFWidgetElementState createState() => FlutterShadcnProgressState(this); } @@ -71,10 +142,25 @@ class FlutterShadcnProgressState extends WebFWidgetElementState { @override Widget build(BuildContext context) { - final progress = widgetElement._max > 0 - ? widgetElement._value / widgetElement._max - : 0.0; + final isIndeterminate = widgetElement._variant == 'indeterminate'; + + final double? progressValue; + if (isIndeterminate) { + progressValue = null; + } else { + progressValue = widgetElement._max > 0 + ? widgetElement._value / widgetElement._max + : 0.0; + } - return ShadProgress(value: progress); + return ShadProgress( + value: progressValue, + backgroundColor: widgetElement._backgroundColor, + color: widgetElement._color, + minHeight: widgetElement._minHeight, + borderRadius: widgetElement._borderRadius != null + ? BorderRadius.circular(widgetElement._borderRadius!) + : null, + ); } } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/progress_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/progress_bindings_generated.dart index 403eb8ac0e..de5b88b19c 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/progress_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/progress_bindings_generated.dart @@ -16,24 +16,52 @@ abstract class FlutterShadcnProgressBindings extends WidgetElement { set max(value); String? get variant; set variant(value); + String? get backgroundColor; + set backgroundColor(value); + String? get color; + set color(value); + String? get minHeight; + set minHeight(value); + String? get borderRadius; + set borderRadius(value); @override void initializeAttributes(Map attributes) { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['max'] = ElementAttributeProperty( getter: () => max?.toString(), - setter: (value) => this.max = value, + setter: (value) => max = value, deleter: () => max = null ); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.toString(), - setter: (value) => this.variant = value, + setter: (value) => variant = value, deleter: () => variant = null ); + attributes['background-color'] = ElementAttributeProperty( + getter: () => backgroundColor?.toString(), + setter: (value) => backgroundColor = value, + deleter: () => backgroundColor = null + ); + attributes['color'] = ElementAttributeProperty( + getter: () => color?.toString(), + setter: (value) => color = value, + deleter: () => color = null + ); + attributes['min-height'] = ElementAttributeProperty( + getter: () => minHeight?.toString(), + setter: (value) => minHeight = value, + deleter: () => minHeight = null + ); + attributes['border-radius'] = ElementAttributeProperty( + getter: () => borderRadius?.toString(), + setter: (value) => borderRadius = value, + deleter: () => borderRadius = null + ); } static StaticDefinedBindingPropertyMap flutterShadcnProgressProperties = { 'value': StaticDefinedBindingProperty( @@ -51,6 +79,26 @@ abstract class FlutterShadcnProgressBindings extends WidgetElement { setter: (element, value) => castToType(element).variant = value, ), + 'backgroundColor': StaticDefinedBindingProperty( + getter: (element) => castToType(element).backgroundColor, + setter: (element, value) => + castToType(element).backgroundColor = value, + ), + 'color': StaticDefinedBindingProperty( + getter: (element) => castToType(element).color, + setter: (element, value) => + castToType(element).color = value, + ), + 'minHeight': StaticDefinedBindingProperty( + getter: (element) => castToType(element).minHeight, + setter: (element, value) => + castToType(element).minHeight = value, + ), + 'borderRadius': StaticDefinedBindingProperty( + getter: (element) => castToType(element).borderRadius, + setter: (element, value) => + castToType(element).borderRadius = value, + ), }; @override List get properties => [ diff --git a/native_uis/webf_shadcn_ui/lib/src/components/radio.d.ts b/native_uis/webf_shadcn_ui/lib/src/components/radio.d.ts deleted file mode 100644 index 4b55b019f0..0000000000 --- a/native_uis/webf_shadcn_ui/lib/src/components/radio.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. - * Licensed under the Apache License, Version 2.0. - */ - -/** - * Properties for - * - * Container for radio button groups. - * - * @example - * ```html - * - * Option 1 - * Option 2 - * - * ``` - */ -interface FlutterShadcnRadioProperties { - /** - * Currently selected value. - */ - value?: string; - - /** - * Disable all radio items. - */ - disabled?: boolean; - - /** - * Orientation of the radio group. - * Options: 'horizontal', 'vertical' - * Default: 'vertical' - */ - orientation?: string; -} - -/** - * Events emitted by - */ -interface FlutterShadcnRadioEvents { - /** Fired when selection changes. */ - change: Event; -} - -/** - * Properties for - * - * Individual radio button option. - */ -interface FlutterShadcnRadioItemProperties { - /** - * Value of this radio option. - */ - value: string; - - /** - * Disable this specific radio item. - */ - disabled?: boolean; -} - -interface FlutterShadcnRadioItemEvents {} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/radio.dart b/native_uis/webf_shadcn_ui/lib/src/components/radio.dart deleted file mode 100644 index 879fb39dc7..0000000000 --- a/native_uis/webf_shadcn_ui/lib/src/components/radio.dart +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. - * Licensed under the Apache License, Version 2.0. - */ - -import 'package:flutter/material.dart'; -import 'package:shadcn_ui/shadcn_ui.dart'; -import 'package:webf/rendering.dart'; -import 'package:webf/webf.dart'; - -import 'radio_bindings_generated.dart'; - -/// WebF custom element that wraps shadcn_ui [ShadRadioGroup]. -/// -/// Exposed as `` in the DOM. -class FlutterShadcnRadio extends FlutterShadcnRadioBindings { - FlutterShadcnRadio(super.context); - - String? _value; - bool _disabled = false; - String _orientation = 'vertical'; - - @override - String? get value => _value; - - @override - set value(value) { - final String? v = value?.toString(); - if (v != _value) { - _value = v; - state?.requestUpdateState(() {}); - } - } - - @override - bool get disabled => _disabled; - - @override - set disabled(value) { - final bool v = value == true || value == 'true' || value == ''; - if (v != _disabled) { - _disabled = v; - state?.requestUpdateState(() {}); - } - } - - @override - String? get orientation => _orientation; - - @override - set orientation(value) { - final String newValue = value?.toString() ?? 'vertical'; - if (newValue != _orientation) { - _orientation = newValue; - state?.requestUpdateState(() {}); - } - } - - bool get isHorizontal => _orientation.toLowerCase() == 'horizontal'; - - @override - WebFWidgetElementState createState() => FlutterShadcnRadioState(this); -} - -class FlutterShadcnRadioState extends WebFWidgetElementState { - FlutterShadcnRadioState(super.widgetElement); - - @override - FlutterShadcnRadio get widgetElement => - super.widgetElement as FlutterShadcnRadio; - - List _getRadioItems() { - return widgetElement.childNodes - .whereType() - .toList(); - } - - @override - Widget build(BuildContext context) { - final items = _getRadioItems(); - - final radioItems = items.map((item) { - Widget? labelWidget; - if (item.childNodes.isNotEmpty) { - labelWidget = WebFWidgetElementChild( - child: item.childNodes.first.toWidget(), - ); - } - - return ShadRadio( - value: item._itemValue ?? '', - enabled: !widgetElement.disabled && !item._itemDisabled, - label: labelWidget, - ); - }).toList(); - - return ShadRadioGroup( - initialValue: widgetElement.value, - enabled: !widgetElement.disabled, - onChanged: (value) { - widgetElement._value = value; - widgetElement.dispatchEvent(Event('change')); - }, - items: radioItems, - ); - } -} - -/// WebF custom element for individual radio items. -/// -/// Exposed as `` in the DOM. -class FlutterShadcnRadioItem extends WidgetElement { - FlutterShadcnRadioItem(super.context); - - String? _itemValue; - bool _itemDisabled = false; - - String? get value => _itemValue; - - set value(value) { - final String? v = value?.toString(); - if (v != _itemValue) { - _itemValue = v; - _notifyParent(); - } - } - - bool get disabled => _itemDisabled; - - set disabled(value) { - final bool v = value == true || value == 'true' || value == ''; - if (v != _itemDisabled) { - _itemDisabled = v; - _notifyParent(); - } - } - - void _notifyParent() { - final parent = parentNode; - if (parent is FlutterShadcnRadio) { - parent.state?.requestUpdateState(() {}); - } - } - - @override - void initializeAttributes(Map attributes) { - super.initializeAttributes(attributes); - attributes['value'] = ElementAttributeProperty( - getter: () => value?.toString(), - setter: (v) => value = v, - deleter: () => value = null, - ); - attributes['disabled'] = ElementAttributeProperty( - getter: () => disabled.toString(), - setter: (value) => disabled = value == 'true' || value == '', - deleter: () => disabled = false, - ); - } - - @override - WebFWidgetElementState createState() => FlutterShadcnRadioItemState(this); -} - -class FlutterShadcnRadioItemState extends WebFWidgetElementState { - FlutterShadcnRadioItemState(super.widgetElement); - - @override - Widget build(BuildContext context) { - // This widget is built by the parent FlutterShadcnRadio - return const SizedBox.shrink(); - } -} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/radio_group.d.ts b/native_uis/webf_shadcn_ui/lib/src/components/radio_group.d.ts new file mode 100644 index 0000000000..bfd9a819ba --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/radio_group.d.ts @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ + +/** + * Properties for + * + * Container for radio button groups. + * + * @example + * ```html + * + * Option 1 + * Option 2 + * + * ``` + */ +interface FlutterShadcnRadioGroupProperties { + /** + * Currently selected value. + */ + value?: string; + + /** + * Disable all radio items. + */ + disabled?: boolean; + + /** + * Orientation of the radio group. + * Options: 'horizontal', 'vertical' + * Default: 'vertical' + */ + orientation?: string; +} + +/** + * Events emitted by + */ +interface FlutterShadcnRadioGroupEvents { + /** Fired when selection changes. detail.value contains the selected value. */ + change: CustomEvent<{ value: string }>; +} + +/** + * Properties for + * + * Individual radio button option. + */ +interface FlutterShadcnRadioGroupItemProperties { + /** + * Value of this radio option. + */ + value: string; + + /** + * Disable this specific radio item. + */ + disabled?: boolean; +} + +interface FlutterShadcnRadioGroupItemEvents {} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/radio_group.dart b/native_uis/webf_shadcn_ui/lib/src/components/radio_group.dart new file mode 100644 index 0000000000..a4903baed4 --- /dev/null +++ b/native_uis/webf_shadcn_ui/lib/src/components/radio_group.dart @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2024-present The OpenWebF Company. All rights reserved. + * Licensed under the Apache License, Version 2.0. + */ + +import 'package:flutter/material.dart'; +import 'package:shadcn_ui/shadcn_ui.dart'; +import 'package:webf/webf.dart'; + +import 'radio_group_bindings_generated.dart'; + +/// WebF custom element that wraps shadcn_ui [ShadRadioGroup]. +/// +/// Exposed as `` in the DOM. +/// +/// Note: We render radio items manually rather than using [ShadRadioGroup] +/// because [ShadRadio] relies on [ShadProvider] (InheritedWidget) which +/// does not work correctly in WebF's widget tree. +class FlutterShadcnRadioGroup extends FlutterShadcnRadioGroupBindings { + FlutterShadcnRadioGroup(super.context); + + String? _value; + bool _disabled = false; + String _orientation = 'vertical'; + + @override + String? get value => _value; + + @override + set value(value) { + final String? v = value?.toString(); + if (v != _value) { + _value = v; + state?.requestUpdateState(() {}); + } + } + + @override + bool get disabled => _disabled; + + @override + set disabled(value) { + final bool v = value == true || value == 'true' || value == ''; + if (v != _disabled) { + _disabled = v; + state?.requestUpdateState(() {}); + } + } + + @override + String? get orientation => _orientation; + + @override + set orientation(value) { + final String newValue = value?.toString() ?? 'vertical'; + if (newValue != _orientation) { + _orientation = newValue; + state?.requestUpdateState(() {}); + } + } + + bool get isHorizontal => _orientation.toLowerCase() == 'horizontal'; + + @override + WebFWidgetElementState createState() => FlutterShadcnRadioGroupState(this); +} + +class FlutterShadcnRadioGroupState extends WebFWidgetElementState { + FlutterShadcnRadioGroupState(super.widgetElement); + + @override + FlutterShadcnRadioGroup get widgetElement => + super.widgetElement as FlutterShadcnRadioGroup; + + /// Recursively find all [FlutterShadcnRadioGroupItem] descendants. + List _getRadioItems() { + return _findItemsRecursive(widgetElement.childNodes); + } + + List _findItemsRecursive( + Iterable nodes) { + final items = []; + for (final node in nodes) { + if (node is FlutterShadcnRadioGroupItem) { + items.add(node); + } else if (node.childNodes.isNotEmpty) { + items.addAll(_findItemsRecursive(node.childNodes)); + } + } + return items; + } + + /// Extract text content from a list of nodes recursively. + String _extractTextContent(Iterable nodes) { + final buffer = StringBuffer(); + for (final node in nodes) { + if (node is TextNode) { + buffer.write(node.data); + } else if (node.childNodes.isNotEmpty) { + buffer.write(_extractTextContent(node.childNodes)); + } + } + return buffer.toString().trim(); + } + + void _selectValue(String? itemValue) { + if (widgetElement.disabled) return; + if (itemValue != null && itemValue != widgetElement._value) { + widgetElement._value = itemValue; + widgetElement + .dispatchEvent(CustomEvent('change', detail: {'value': itemValue})); + setState(() {}); + } + } + + String? _resolveItemValue(FlutterShadcnRadioGroupItem item) { + final String? internalValue = item._itemValue; + if (internalValue != null && internalValue.isNotEmpty) { + return internalValue; + } + + final String? attrValue = item.getAttribute('value'); + if (attrValue != null && attrValue.isNotEmpty) { + return attrValue; + } + + return null; + } + + @override + Widget build(BuildContext context) { + final theme = ShadTheme.of(context); + final items = _getRadioItems(); + + final radioWidgets = + items.map((item) => _buildRadioItem(item, theme)).toList(); + + if (widgetElement.isHorizontal) { + return Wrap( + spacing: theme.radioTheme.spacing ?? 4, + runSpacing: theme.radioTheme.runSpacing ?? 0, + children: radioWidgets, + ); + } + + return Wrap( + direction: Axis.vertical, + spacing: theme.radioTheme.spacing ?? 4, + runSpacing: theme.radioTheme.runSpacing ?? 0, + children: radioWidgets, + ); + } + + /// Build a single radio item matching [ShadRadio] visual style. + Widget _buildRadioItem( + FlutterShadcnRadioGroupItem item, + ShadThemeData theme, + ) { + var itemValue = _resolveItemValue(item); + final isEnabled = !widgetElement.disabled && !item._itemDisabled; + + // Read theme values matching ShadRadio defaults + final effectiveSize = theme.radioTheme.size ?? 16.0; + final effectiveCircleSize = theme.radioTheme.circleSize ?? 10.0; + final effectiveColor = + theme.radioTheme.color ?? theme.colorScheme.primary; + final effectivePadding = theme.radioTheme.padding ?? + const EdgeInsetsDirectional.only(start: 8); + final effectiveRadioPadding = + theme.radioTheme.radioPadding ?? const EdgeInsets.only(top: 1); + + // Extract label text from child nodes (like accordion pattern) + final labelText = _extractTextContent(item.childNodes); + + // Defensive fallback when value binding is not available. + if (itemValue == null && labelText.isNotEmpty) { + itemValue = labelText.toLowerCase(); + } + + final isSelected = itemValue != null && widgetElement.value == itemValue; + + // Radio circle: outer ring + inner fill when selected + final radioCircle = SizedBox.square( + dimension: effectiveSize, + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: effectiveColor, + width: 1, + ), + ), + child: isSelected + ? Center( + child: SizedBox.square( + dimension: effectiveCircleSize, + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: effectiveColor, + ), + ), + ), + ) + : null, + ), + ); + + Widget row = Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: effectiveRadioPadding, + child: radioCircle, + ), + if (labelText.isNotEmpty) + Flexible( + child: Padding( + padding: effectivePadding, + child: Text( + labelText, + style: theme.textTheme.muted.copyWith( + fontWeight: FontWeight.w500, + color: theme.colorScheme.foreground, + ), + ), + ), + ), + ], + ), + ); + + if (!isEnabled) { + return AbsorbPointer( + absorbing: true, + child: Opacity( + opacity: theme.disabledOpacity, + child: row, + ), + ); + } + + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _selectValue(itemValue), + child: row, + ); + } +} + +/// WebF custom element for individual radio items. +/// +/// Exposed as `` in the DOM. +class FlutterShadcnRadioGroupItem extends WidgetElement { + FlutterShadcnRadioGroupItem(super.context); + + String? _itemValue; + bool _itemDisabled = false; + + String? get value => _itemValue; + + set value(value) { + final String? v = value?.toString(); + if (v != _itemValue) { + _itemValue = v; + _notifyParentGroup(); + } + } + + bool get disabled => _itemDisabled; + + set disabled(value) { + final bool v = value == true || value == 'true' || value == ''; + if (v != _itemDisabled) { + _itemDisabled = v; + _notifyParentGroup(); + } + } + + /// Walk up the tree to find the parent [FlutterShadcnRadioGroup]. + void _notifyParentGroup() { + Node? current = parentNode; + while (current != null) { + if (current is FlutterShadcnRadioGroup) { + current.state?.requestUpdateState(() {}); + return; + } + current = current.parentNode; + } + } + + @override + void initializeAttributes(Map attributes) { + super.initializeAttributes(attributes); + attributes['value'] = ElementAttributeProperty( + getter: () => value?.toString(), + setter: (v) => value = v, + deleter: () => value = null, + ); + attributes['disabled'] = ElementAttributeProperty( + getter: () => disabled.toString(), + setter: (value) => disabled = value == 'true' || value == '', + deleter: () => disabled = false, + ); + } + + @override + WebFWidgetElementState createState() => + FlutterShadcnRadioGroupItemState(this); +} + +class FlutterShadcnRadioGroupItemState extends WebFWidgetElementState { + FlutterShadcnRadioGroupItemState(super.widgetElement); + + @override + Widget build(BuildContext context) { + // This widget is built by the parent FlutterShadcnRadioGroup + return const SizedBox.shrink(); + } +} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/radio_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/radio_group_bindings_generated.dart similarity index 62% rename from native_uis/webf_shadcn_ui/lib/src/components/radio_bindings_generated.dart rename to native_uis/webf_shadcn_ui/lib/src/components/radio_group_bindings_generated.dart index 64ba73ceff..086db74dde 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/radio_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/radio_group_bindings_generated.dart @@ -8,8 +8,8 @@ // ignore_for_file: library_private_types_in_public_api // ignore_for_file: prefer_void_to_null import 'package:webf/webf.dart'; -abstract class FlutterShadcnRadioBindings extends WidgetElement { - FlutterShadcnRadioBindings(super.context); +abstract class FlutterShadcnRadioGroupBindings extends WidgetElement { + FlutterShadcnRadioGroupBindings(super.context); String? get value; set value(value); bool get disabled; @@ -21,40 +21,40 @@ abstract class FlutterShadcnRadioBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['orientation'] = ElementAttributeProperty( getter: () => orientation?.toString(), - setter: (value) => this.orientation = value, + setter: (value) => orientation = value, deleter: () => orientation = null ); } - static StaticDefinedBindingPropertyMap flutterShadcnRadioProperties = { + static StaticDefinedBindingPropertyMap flutterShadcnRadioGroupProperties = { 'value': StaticDefinedBindingProperty( - getter: (element) => castToType(element).value, + getter: (element) => castToType(element).value, setter: (element, value) => - castToType(element).value = value, + castToType(element).value = value, ), 'disabled': StaticDefinedBindingProperty( - getter: (element) => castToType(element).disabled, + getter: (element) => castToType(element).disabled, setter: (element, value) => - castToType(element).disabled = value, + castToType(element).disabled = value, ), 'orientation': StaticDefinedBindingProperty( - getter: (element) => castToType(element).orientation, + getter: (element) => castToType(element).orientation, setter: (element, value) => - castToType(element).orientation = value, + castToType(element).orientation = value, ), }; @override List get properties => [ ...super.properties, - flutterShadcnRadioProperties, + flutterShadcnRadioGroupProperties, ]; -} \ No newline at end of file +} diff --git a/native_uis/webf_shadcn_ui/lib/src/components/scroll_area_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/scroll_area_bindings_generated.dart index a51bc97c4e..f035ccfd8a 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/scroll_area_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/scroll_area_bindings_generated.dart @@ -17,7 +17,7 @@ abstract class FlutterShadcnScrollAreaBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['orientation'] = ElementAttributeProperty( getter: () => orientation?.toString(), - setter: (value) => this.orientation = value, + setter: (value) => orientation = value, deleter: () => orientation = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/select_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/select_bindings_generated.dart index 5cfb73dfa1..33c1e7d70e 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/select_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/select_bindings_generated.dart @@ -31,42 +31,42 @@ abstract class FlutterShadcnSelectBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['multiple'] = ElementAttributeProperty( getter: () => multiple.toString(), - setter: (value) => this.multiple = value == 'true' || value == '', + setter: (value) => multiple = value == 'true' || value == '', deleter: () => multiple = false ); attributes['searchable'] = ElementAttributeProperty( getter: () => searchable.toString(), - setter: (value) => this.searchable = value == 'true' || value == '', + setter: (value) => searchable = value == 'true' || value == '', deleter: () => searchable = false ); attributes['search-placeholder'] = ElementAttributeProperty( getter: () => searchPlaceholder?.toString(), - setter: (value) => this.searchPlaceholder = value, + setter: (value) => searchPlaceholder = value, deleter: () => searchPlaceholder = null ); attributes['allow-deselection'] = ElementAttributeProperty( getter: () => allowDeselection.toString(), - setter: (value) => this.allowDeselection = value == 'true' || value == '', + setter: (value) => allowDeselection = value == 'true' || value == '', deleter: () => allowDeselection = false ); attributes['close-on-select'] = ElementAttributeProperty( getter: () => closeOnSelect.toString(), - setter: (value) => this.closeOnSelect = value == 'true' || value == '', + setter: (value) => closeOnSelect = value == 'true' || value == '', deleter: () => closeOnSelect = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/separator_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/separator_bindings_generated.dart index 1a96ad0b35..013cc913c8 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/separator_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/separator_bindings_generated.dart @@ -17,7 +17,7 @@ abstract class FlutterShadcnSeparatorBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['orientation'] = ElementAttributeProperty( getter: () => orientation?.toString(), - setter: (value) => this.orientation = value, + setter: (value) => orientation = value, deleter: () => orientation = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/sheet_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/sheet_bindings_generated.dart index 231618aeec..58a1acb87b 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/sheet_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/sheet_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnSheetBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['open'] = ElementAttributeProperty( getter: () => open.toString(), - setter: (value) => this.open = value == 'true' || value == '', + setter: (value) => open = value == 'true' || value == '', deleter: () => open = false ); attributes['side'] = ElementAttributeProperty( getter: () => side?.toString(), - setter: (value) => this.side = value, + setter: (value) => side = value, deleter: () => side = null ); attributes['close-on-outside-click'] = ElementAttributeProperty( getter: () => closeOnOutsideClick.toString(), - setter: (value) => this.closeOnOutsideClick = value == 'true' || value == '', + setter: (value) => closeOnOutsideClick = value == 'true' || value == '', deleter: () => closeOnOutsideClick = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/skeleton_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/skeleton_bindings_generated.dart index 5faa5e6fc5..885bb9f176 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/skeleton_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/skeleton_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnSkeletonBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['width'] = ElementAttributeProperty( getter: () => width?.toString(), - setter: (value) => this.width = value, + setter: (value) => width = value, deleter: () => width = null ); attributes['height'] = ElementAttributeProperty( getter: () => height?.toString(), - setter: (value) => this.height = value, + setter: (value) => height = value, deleter: () => height = null ); attributes['circle'] = ElementAttributeProperty( getter: () => circle.toString(), - setter: (value) => this.circle = value == 'true' || value == '', + setter: (value) => circle = value == 'true' || value == '', deleter: () => circle = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/slider_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/slider_bindings_generated.dart index 7e558ef89e..895f7bfca3 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/slider_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/slider_bindings_generated.dart @@ -27,32 +27,32 @@ abstract class FlutterShadcnSliderBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['min'] = ElementAttributeProperty( getter: () => min?.toString(), - setter: (value) => this.min = value, + setter: (value) => min = value, deleter: () => min = null ); attributes['max'] = ElementAttributeProperty( getter: () => max?.toString(), - setter: (value) => this.max = value, + setter: (value) => max = value, deleter: () => max = null ); attributes['step'] = ElementAttributeProperty( getter: () => step?.toString(), - setter: (value) => this.step = value, + setter: (value) => step = value, deleter: () => step = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['orientation'] = ElementAttributeProperty( getter: () => orientation?.toString(), - setter: (value) => this.orientation = value, + setter: (value) => orientation = value, deleter: () => orientation = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/switch_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/switch_bindings_generated.dart index b168635a01..6dbd9143bd 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/switch_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/switch_bindings_generated.dart @@ -19,12 +19,12 @@ abstract class FlutterShadcnSwitchBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['checked'] = ElementAttributeProperty( getter: () => checked.toString(), - setter: (value) => this.checked = value == 'true' || value == '', + setter: (value) => checked = value == 'true' || value == '', deleter: () => checked = false ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/tabs_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/tabs_bindings_generated.dart index 2239d012e0..65f0d6c82f 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/tabs_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/tabs_bindings_generated.dart @@ -19,12 +19,12 @@ abstract class FlutterShadcnTabsBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['default-value'] = ElementAttributeProperty( getter: () => defaultValue?.toString(), - setter: (value) => this.defaultValue = value, + setter: (value) => defaultValue = value, deleter: () => defaultValue = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/textarea_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/textarea_bindings_generated.dart index 48af42d1a6..2575203941 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/textarea_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/textarea_bindings_generated.dart @@ -31,42 +31,42 @@ abstract class FlutterShadcnTextareaBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['rows'] = ElementAttributeProperty( getter: () => rows?.toString(), - setter: (value) => this.rows = value, + setter: (value) => rows = value, deleter: () => rows = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['readonly'] = ElementAttributeProperty( getter: () => readonly.toString(), - setter: (value) => this.readonly = value == 'true' || value == '', + setter: (value) => readonly = value == 'true' || value == '', deleter: () => readonly = false ); attributes['maxlength'] = ElementAttributeProperty( getter: () => maxlength?.toString(), - setter: (value) => this.maxlength = value, + setter: (value) => maxlength = value, deleter: () => maxlength = null ); attributes['required'] = ElementAttributeProperty( getter: () => required.toString(), - setter: (value) => this.required = value == 'true' || value == '', + setter: (value) => required = value == 'true' || value == '', deleter: () => required = false ); attributes['autofocus'] = ElementAttributeProperty( getter: () => autofocus.toString(), - setter: (value) => this.autofocus = value == 'true' || value == '', + setter: (value) => autofocus = value == 'true' || value == '', deleter: () => autofocus = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/time_picker_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/time_picker_bindings_generated.dart index 81aaeb0a35..b8cdd80dbc 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/time_picker_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/time_picker_bindings_generated.dart @@ -23,22 +23,22 @@ abstract class FlutterShadcnTimePickerBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['value'] = ElementAttributeProperty( getter: () => value?.toString(), - setter: (value) => this.value = value, + setter: (value) => value = value, deleter: () => value = null ); attributes['placeholder'] = ElementAttributeProperty( getter: () => placeholder?.toString(), - setter: (value) => this.placeholder = value, + setter: (value) => placeholder = value, deleter: () => placeholder = null ); attributes['disabled'] = ElementAttributeProperty( getter: () => disabled.toString(), - setter: (value) => this.disabled = value == 'true' || value == '', + setter: (value) => disabled = value == 'true' || value == '', deleter: () => disabled = false ); attributes['use-24-hour'] = ElementAttributeProperty( getter: () => use24Hour.toString(), - setter: (value) => this.use24Hour = value == 'true' || value == '', + setter: (value) => use24Hour = value == 'true' || value == '', deleter: () => use24Hour = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/toast_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/toast_bindings_generated.dart index ff3e321b6c..2bd02a881f 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/toast_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/toast_bindings_generated.dart @@ -25,27 +25,27 @@ abstract class FlutterShadcnToastBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['variant'] = ElementAttributeProperty( getter: () => variant?.toString(), - setter: (value) => this.variant = value, + setter: (value) => variant = value, deleter: () => variant = null ); attributes['title'] = ElementAttributeProperty( getter: () => title?.toString(), - setter: (value) => this.title = value, + setter: (value) => title = value, deleter: () => title = null ); attributes['description'] = ElementAttributeProperty( getter: () => description?.toString(), - setter: (value) => this.description = value, + setter: (value) => description = value, deleter: () => description = null ); attributes['duration'] = ElementAttributeProperty( getter: () => duration?.toString(), - setter: (value) => this.duration = value, + setter: (value) => duration = value, deleter: () => duration = null ); attributes['closable'] = ElementAttributeProperty( getter: () => closable.toString(), - setter: (value) => this.closable = value == 'true' || value == '', + setter: (value) => closable = value == 'true' || value == '', deleter: () => closable = false ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/components/tooltip_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/components/tooltip_bindings_generated.dart index 5894caaeae..8eccd442e6 100644 --- a/native_uis/webf_shadcn_ui/lib/src/components/tooltip_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/components/tooltip_bindings_generated.dart @@ -23,22 +23,22 @@ abstract class FlutterShadcnTooltipBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['content'] = ElementAttributeProperty( getter: () => content?.toString(), - setter: (value) => this.content = value, + setter: (value) => content = value, deleter: () => content = null ); attributes['show-delay'] = ElementAttributeProperty( getter: () => showDelay?.toString(), - setter: (value) => this.showDelay = value, + setter: (value) => showDelay = value, deleter: () => showDelay = null ); attributes['hide-delay'] = ElementAttributeProperty( getter: () => hideDelay?.toString(), - setter: (value) => this.hideDelay = value, + setter: (value) => hideDelay = value, deleter: () => hideDelay = null ); attributes['placement'] = ElementAttributeProperty( getter: () => placement?.toString(), - setter: (value) => this.placement = value, + setter: (value) => placement = value, deleter: () => placement = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/src/theme/theme_bindings_generated.dart b/native_uis/webf_shadcn_ui/lib/src/theme/theme_bindings_generated.dart index f9e7dcba7b..0f7407a6c2 100644 --- a/native_uis/webf_shadcn_ui/lib/src/theme/theme_bindings_generated.dart +++ b/native_uis/webf_shadcn_ui/lib/src/theme/theme_bindings_generated.dart @@ -21,17 +21,17 @@ abstract class FlutterShadcnThemeBindings extends WidgetElement { super.initializeAttributes(attributes); attributes['color-scheme'] = ElementAttributeProperty( getter: () => colorScheme?.toString(), - setter: (value) => this.colorScheme = value, + setter: (value) => colorScheme = value, deleter: () => colorScheme = null ); attributes['brightness'] = ElementAttributeProperty( getter: () => brightness?.toString(), - setter: (value) => this.brightness = value, + setter: (value) => brightness = value, deleter: () => brightness = null ); attributes['radius'] = ElementAttributeProperty( getter: () => radius?.toString(), - setter: (value) => this.radius = value, + setter: (value) => radius = value, deleter: () => radius = null ); } diff --git a/native_uis/webf_shadcn_ui/lib/webf_shadcn_ui.dart b/native_uis/webf_shadcn_ui/lib/webf_shadcn_ui.dart index 313081ca67..2b375662b6 100644 --- a/native_uis/webf_shadcn_ui/lib/webf_shadcn_ui.dart +++ b/native_uis/webf_shadcn_ui/lib/webf_shadcn_ui.dart @@ -45,12 +45,13 @@ export 'src/components/icon_button.dart'; export 'src/components/input.dart'; export 'src/components/textarea.dart'; export 'src/components/checkbox.dart'; -export 'src/components/radio.dart'; +export 'src/components/radio_group.dart'; export 'src/components/switch.dart'; export 'src/components/select.dart'; export 'src/components/slider.dart'; export 'src/components/combobox.dart'; export 'src/components/form.dart'; +export 'src/components/input_otp.dart'; // Display Components export 'src/components/card.dart'; @@ -70,6 +71,7 @@ export 'src/components/popover.dart'; export 'src/components/breadcrumb.dart'; export 'src/components/dropdown_menu.dart'; export 'src/components/context_menu.dart'; +export 'src/components/menubar.dart'; // Data Display export 'src/components/table.dart'; @@ -91,12 +93,13 @@ import 'src/components/icon_button.dart'; import 'src/components/input.dart'; import 'src/components/textarea.dart'; import 'src/components/checkbox.dart'; -import 'src/components/radio.dart'; +import 'src/components/radio_group.dart'; import 'src/components/switch.dart'; import 'src/components/select.dart'; import 'src/components/slider.dart'; import 'src/components/combobox.dart'; import 'src/components/form.dart'; +import 'src/components/input_otp.dart'; import 'src/components/card.dart'; import 'src/components/alert.dart'; import 'src/components/badge.dart'; @@ -112,6 +115,7 @@ import 'src/components/popover.dart'; import 'src/components/breadcrumb.dart'; import 'src/components/dropdown_menu.dart'; import 'src/components/context_menu.dart'; +import 'src/components/menubar.dart'; import 'src/components/table.dart'; import 'src/components/accordion.dart'; import 'src/components/calendar.dart'; @@ -151,9 +155,9 @@ void installWebFShadcnUI() { WebF.defineCustomElement( 'flutter-shadcn-checkbox', (context) => FlutterShadcnCheckbox(context)); WebF.defineCustomElement( - 'flutter-shadcn-radio', (context) => FlutterShadcnRadio(context)); + 'flutter-shadcn-radio-group', (context) => FlutterShadcnRadioGroup(context)); WebF.defineCustomElement( - 'flutter-shadcn-radio-item', (context) => FlutterShadcnRadioItem(context)); + 'flutter-shadcn-radio-group-item', (context) => FlutterShadcnRadioGroupItem(context)); WebF.defineCustomElement( 'flutter-shadcn-switch', (context) => FlutterShadcnSwitch(context)); WebF.defineCustomElement( @@ -180,6 +184,14 @@ void installWebFShadcnUI() { 'flutter-shadcn-form-description', (context) => FlutterShadcnFormDescription(context)); WebF.defineCustomElement( 'flutter-shadcn-form-message', (context) => FlutterShadcnFormMessage(context)); + WebF.defineCustomElement( + 'flutter-shadcn-input-otp', (context) => FlutterShadcnInputOtp(context)); + WebF.defineCustomElement( + 'flutter-shadcn-input-otp-group', (context) => FlutterShadcnInputOtpGroup(context)); + WebF.defineCustomElement( + 'flutter-shadcn-input-otp-slot', (context) => FlutterShadcnInputOtpSlot(context)); + WebF.defineCustomElement( + 'flutter-shadcn-input-otp-separator', (context) => FlutterShadcnInputOtpSeparator(context)); // Display Components WebF.defineCustomElement( @@ -306,6 +318,32 @@ void installWebFShadcnUI() { 'flutter-shadcn-context-menu-radio-group', (context) => FlutterShadcnContextMenuRadioGroup(context)); WebF.defineCustomElement( 'flutter-shadcn-context-menu-radio-item', (context) => FlutterShadcnContextMenuRadioItem(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar', (context) => FlutterShadcnMenubar(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-menu', (context) => FlutterShadcnMenubarMenu(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-trigger', (context) => FlutterShadcnMenubarTrigger(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-content', (context) => FlutterShadcnMenubarContent(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-item', (context) => FlutterShadcnMenubarItem(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-separator', (context) => FlutterShadcnMenubarSeparator(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-label', (context) => FlutterShadcnMenubarLabel(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-sub', (context) => FlutterShadcnMenubarSub(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-sub-trigger', (context) => FlutterShadcnMenubarSubTrigger(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-sub-content', (context) => FlutterShadcnMenubarSubContent(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-checkbox-item', (context) => FlutterShadcnMenubarCheckboxItem(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-radio-group', (context) => FlutterShadcnMenubarRadioGroup(context)); + WebF.defineCustomElement( + 'flutter-shadcn-menubar-radio-item', (context) => FlutterShadcnMenubarRadioItem(context)); // Data Display WebF.defineCustomElement( diff --git a/packages/react-shadcn-ui/.gitignore b/packages/react-shadcn-ui/.gitignore new file mode 100644 index 0000000000..2b60337458 --- /dev/null +++ b/packages/react-shadcn-ui/.gitignore @@ -0,0 +1,9 @@ +node_modules/ +/lib/ +dist/ +.DS_Store +*.log +*.tsbuildinfo +.env +.env.local +.env.*.local \ No newline at end of file diff --git a/packages/react-shadcn-ui/README.md b/packages/react-shadcn-ui/README.md new file mode 100644 index 0000000000..3457799b8b --- /dev/null +++ b/packages/react-shadcn-ui/README.md @@ -0,0 +1,206 @@ +# webf_shadcn_ui + +shadcn/ui style components for WebF applications. This package provides [shadcn_ui](https://pub.dev/packages/shadcn_ui) Flutter widgets wrapped as HTML custom elements for use in WebF. + +## Features + +- 40+ UI components matching shadcn/ui design +- Full theming support with 12 color schemes +- Light/Dark mode support +- TypeScript definitions for React/Vue code generation +- Seamless integration with WebF applications + +## Installation + +Add this to your package's `pubspec.yaml` file: + +```yaml +dependencies: + webf_shadcn_ui: ^0.1.0 +``` + +## Quick Start + +1. Install the custom elements in your main function: + +```dart +import 'package:webf_shadcn_ui/webf_shadcn_ui.dart'; + +void main() { + installWebFShadcnUI(); + runApp(MyApp()); +} +``` + +2. Use the components in your HTML: + +```html + + + + Welcome + Get started with shadcn components + + + Click me + + + +``` + +## Available Components + +### Theming +- `` - Theme provider with color scheme and brightness support + +### Form Controls +- `` - Button with variants (default, secondary, destructive, outline, ghost, link) +- `` - Text input field +- `` - Multi-line text input +- `` - Checkbox control +- `` - Radio button group +- `` - Toggle switch +- `` - Dropdown select +- `` - Range slider +- `` - Searchable select +- `` - Form container with field components + +### Display Components +- `` - Card container with header, content, footer slots +- `` - Alert message with title and description +- `` - Badge/label component +- `` - User avatar with fallback +- `` - Toast notification +- `` - Hover tooltip +- `` - Progress bar +- `` - Visual separator + +### Navigation/Layout +- `` - Tabbed interface +- `` - Modal dialog +- `` - Slide-out panel +- `` - Floating content container +- `` - Breadcrumb navigation +- `` - Dropdown menu +- `` - Right-click context menu + +### Data Display +- `` - Data table +- `` - Collapsible sections +- `` - Date calendar +- `` - Date picker with popover +- `` - Time picker +- `` - Image with loading states + +### Advanced +- `` - Scrollable container +- `` - Loading placeholder +- `` - Collapsible section + +## CSS Customization + +### Button Text Styling + +The `` component supports CSS customization for text styles while automatically handling the text color based on the button variant and theme. + +**What CSS properties work on button children:** +- `font-size` / `font-weight` / `font-family` +- `letter-spacing` / `word-spacing` +- `text-decoration` / `font-style` +- Other text styling properties + +**What's controlled by the button theme:** +- Text color (automatically set based on button variant) + +**Example with inline styles:** + +```html + + Large Bold Text + +``` + +**Example with React and Tailwind:** + +```jsx + + Styled Text + +``` + +This approach ensures: +- CSS styles from your HTML/JSX are preserved (font-size, font-weight, etc.) +- Text color automatically matches the button's theme variant (primary has white text, outline has dark text, etc.) + +### Button Gradient and Shadow + +The button supports CSS `background-image` for gradients and `box-shadow` for shadows, which are passed directly to the underlying Flutter `ShadButton`. + +**Gradient example:** + +```html + + Gradient Button + +``` + +**Shadow example:** + +```html + + Shadow Button + +``` + +**Combined gradient and shadow:** + +```jsx + + Gradient + Shadow + +``` + +**Supported gradient syntax:** +- `linear-gradient(direction, color1, color2, ...)` +- `linear-gradient(angle, color1 stop1, color2 stop2, ...)` + +**Supported shadow syntax:** +- `box-shadow: offset-x offset-y blur-radius spread-radius color` + +## Color Schemes + +The following color schemes are available: +- blue, gray, green, neutral, orange, red, rose, slate, stone, violet, yellow, zinc + +Set the color scheme on the theme provider: + +```html + + + +``` + +## Generating React/Vue Components + +Use the WebF CLI to generate framework-specific packages: + +```bash +# React components +webf codegen webf-shadcn-react \ + --flutter-package-src=./native_uis/webf_shadcn_ui \ + --framework=react + +# Vue components +webf codegen webf-shadcn-vue \ + --flutter-package-src=./native_uis/webf_shadcn_ui \ + --framework=vue +``` + +## License + +Apache License 2.0 diff --git a/packages/react-shadcn-ui/global.d.ts b/packages/react-shadcn-ui/global.d.ts new file mode 100644 index 0000000000..bf744d7620 --- /dev/null +++ b/packages/react-shadcn-ui/global.d.ts @@ -0,0 +1,2 @@ +type double = number; +type int = number; diff --git a/packages/react-shadcn-ui/package-lock.json b/packages/react-shadcn-ui/package-lock.json new file mode 100644 index 0000000000..c7039fe872 --- /dev/null +++ b/packages/react-shadcn-ui/package-lock.json @@ -0,0 +1,1244 @@ +{ + "name": "@openwebf/react-shadcn-ui", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@openwebf/react-shadcn-ui", + "version": "0.1.0", + "license": "ISC", + "devDependencies": { + "@openwebf/react-core-ui": "^0.24.1", + "@types/react": "^19.1.0", + "@types/react-dom": "^19.1.2", + "picomatch": "^4.0.2", + "tsdown": "^0.19.0", + "typescript": "^5.8.3" + }, + "peerDependencies": { + "@openwebf/react-core-ui": "^0.24.1", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@openwebf/react-core-ui": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@openwebf/react-core-ui/-/react-core-ui-0.24.2.tgz", + "integrity": "sha512-CBh1Gg/Fb5FfpNg/zYp3eRmL2gR/CwwoUKrGn+WSCFA76IQdWrghubTlVIOeCyu22WcBUYVF/QSA0NyqKu9Pkg==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.107.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.107.0.tgz", + "integrity": "sha512-QFDRbYfV2LVx8tyqtyiah3jQPUj1mK2+RYwxyFWyGoys6XJnwTdlzO6rdNNHOPorHAu5Uo34oWRKcvNpbJarmQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@quansync/fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-1.0.0.tgz", + "integrity": "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.59.tgz", + "integrity": "sha512-6yLLgyswYwiCfls9+hoNFY9F8TQdwo15hpXDHzlAR0X/GojeKF+AuNcXjYNbOJ4zjl/5D6lliE8CbpB5t1OWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.59.tgz", + "integrity": "sha512-hqGXRc162qCCIOAcHN2Cw4eXiVTwYsMFLOhAy1IG2CxY+dwc/l4Ga+dLPkLor3Ikqy5WDn+7kxHbbh6EmshEpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.59.tgz", + "integrity": "sha512-ezvvGuhteE15JmMhJW0wS7BaXmhwLy1YHeEwievYaPC1PgGD86wgBKfOpHr9tSKllAXbCe0BeeMvasscWLhKdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.59.tgz", + "integrity": "sha512-4fhKVJiEYVd5n6no/mrL3LZ9kByfCGwmONOrdtvx8DJGDQhehH/q3RfhG3V/4jGKhpXgbDjpIjkkFdybCTcgew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.59.tgz", + "integrity": "sha512-T3Y52sW6JAhvIqArBw+wtjNU1Ieaz4g0NBxyjSJoW971nZJBZygNlSYx78G4cwkCmo1dYTciTPDOnQygLV23pA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.59.tgz", + "integrity": "sha512-NIW40jQDSQap2KDdmm9z3B/4OzWJ6trf8dwx3FD74kcQb3v34ThsBFTtzE5KjDuxnxgUlV+DkAu+XgSMKrgufw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.59.tgz", + "integrity": "sha512-CCKEk+H+8c0WGe/8n1E20n85Tq4Pv+HNAbjP1KfUXW+01aCWSMjU56ChNrM2tvHnXicfm7QRNoZyfY8cWh7jLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.59.tgz", + "integrity": "sha512-VlfwJ/HCskPmQi8R0JuAFndySKVFX7yPhE658o27cjSDWWbXVtGkSbwaxstii7Q+3Rz87ZXN+HLnb1kd4R9Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.59.tgz", + "integrity": "sha512-kuO92hTRyGy0Ts3Nsqll0rfO8eFsEJe9dGQGktkQnZ2hrJrDVN0y419dMgKy/gB2S2o7F2dpWhpfQOBehZPwVA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.59.tgz", + "integrity": "sha512-PXAebvNL4sYfCqi8LdY4qyFRacrRoiPZLo3NoUmiTxm7MPtYYR8CNtBGNokqDmMuZIQIecRaD/jbmFAIDz7DxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.59.tgz", + "integrity": "sha512-yJoklQg7XIZq8nAg0bbkEXcDK6sfpjxQGxpg2Nd6ERNtvg+eOaEBRgPww0BVTrYFQzje1pB5qPwC2VnJHT3koQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.59.tgz", + "integrity": "sha512-ljZ4+McmCbIuZwEBaoGtiG8Rq2nJjaXEnLEIx+usWetXn1ECjXY0LAhkELxOV6ytv4ensEmoJJ8nXg47hRMjlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.59.tgz", + "integrity": "sha512-bMY4tTIwbdZljW+xe/ln1hvs0SRitahQSXfWtvgAtIzgSX9Ar7KqJzU7lRm33YTRFIHLULRi53yNjw9nJGd6uQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.59.tgz", + "integrity": "sha512-aoh6LAJRyhtazs98ydgpNOYstxUlsOV1KJXcpf/0c0vFcUA8uyd/hwKRhqE/AAPNqAho9RliGsvitCoOzREoVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/birpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz", + "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dts-resolver": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-2.1.3.tgz", + "integrity": "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "oxc-resolver": ">=11.0.0" + }, + "peerDependenciesMeta": { + "oxc-resolver": { + "optional": true + } + } + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/hookable": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.0.1.tgz", + "integrity": "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-without-cache": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/import-without-cache/-/import-without-cache-0.2.5.tgz", + "integrity": "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/quansync": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", + "integrity": "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.59", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.59.tgz", + "integrity": "sha512-Slm000Gd8/AO9z4Kxl4r8mp/iakrbAuJ1L+7ddpkNxgQ+Vf37WPvY63l3oeyZcfuPD1DRrUYBsRPIXSOhvOsmw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.107.0", + "@rolldown/pluginutils": "1.0.0-beta.59" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.59", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.59", + "@rolldown/binding-darwin-x64": "1.0.0-beta.59", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.59", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.59", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.59", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.59", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.59", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.59", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.59", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.59", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.59", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.59" + } + }, + "node_modules/rolldown-plugin-dts": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.20.0.tgz", + "integrity": "sha512-cLAY1kN2ilTYMfZcFlGWbXnu6Nb+8uwUBsi+Mjbh4uIx7IN8uMOmJ7RxrrRgPsO4H7eSz3E+JwGoL1gyugiyUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "ast-kit": "^2.2.0", + "birpc": "^4.0.0", + "dts-resolver": "^2.1.3", + "get-tsconfig": "^4.13.0", + "obug": "^2.1.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@ts-macro/tsc": "^0.3.6", + "@typescript/native-preview": ">=7.0.0-dev.20250601.1", + "rolldown": "^1.0.0-beta.57", + "typescript": "^5.0.0", + "vue-tsc": "~3.2.0" + }, + "peerDependenciesMeta": { + "@ts-macro/tsc": { + "optional": true + }, + "@typescript/native-preview": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tsdown": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.19.0.tgz", + "integrity": "sha512-uqg8yzlS7GemFWcM6aCp/sptF4bJiJbWUibuHTRLLCBEsGCgJxuqxPhuVTqyHXqoEkh9ohwAdlyDKli5MEWCyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.2.0", + "cac": "^6.7.14", + "defu": "^6.1.4", + "empathic": "^2.0.0", + "hookable": "^6.0.1", + "import-without-cache": "^0.2.5", + "obug": "^2.1.1", + "picomatch": "^4.0.3", + "rolldown": "1.0.0-beta.59", + "rolldown-plugin-dts": "^0.20.0", + "semver": "^7.7.3", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tree-kill": "^1.2.2", + "unconfig-core": "^7.4.2", + "unrun": "^0.2.24" + }, + "bin": { + "tsdown": "dist/run.mjs" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@arethetypeswrong/core": "^0.18.1", + "@vitejs/devtools": "*", + "publint": "^0.3.0", + "typescript": "^5.0.0", + "unplugin-lightningcss": "^0.4.0", + "unplugin-unused": "^0.5.0" + }, + "peerDependenciesMeta": { + "@arethetypeswrong/core": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "publint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "unplugin-lightningcss": { + "optional": true + }, + "unplugin-unused": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unconfig-core": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/unconfig-core/-/unconfig-core-7.4.2.tgz", + "integrity": "sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unrun": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/unrun/-/unrun-0.2.27.tgz", + "integrity": "sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rolldown": "1.0.0-rc.3" + }, + "bin": { + "unrun": "dist/cli.mjs" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/Gugustinette" + }, + "peerDependencies": { + "synckit": "^0.11.11" + }, + "peerDependenciesMeta": { + "synckit": { + "optional": true + } + } + }, + "node_modules/unrun/node_modules/@oxc-project/types": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.112.0.tgz", + "integrity": "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.3.tgz", + "integrity": "sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.3.tgz", + "integrity": "sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.3.tgz", + "integrity": "sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.3.tgz", + "integrity": "sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.3.tgz", + "integrity": "sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.3.tgz", + "integrity": "sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.3.tgz", + "integrity": "sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.3.tgz", + "integrity": "sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.3.tgz", + "integrity": "sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.3.tgz", + "integrity": "sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.3.tgz", + "integrity": "sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.3.tgz", + "integrity": "sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.3.tgz", + "integrity": "sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unrun/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrun/node_modules/rolldown": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.3.tgz", + "integrity": "sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.112.0", + "@rolldown/pluginutils": "1.0.0-rc.3" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.3", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.3", + "@rolldown/binding-darwin-x64": "1.0.0-rc.3", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.3", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.3", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.3", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.3", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.3", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.3", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.3" + } + } + } +} diff --git a/packages/react-shadcn-ui/package.json b/packages/react-shadcn-ui/package.json new file mode 100644 index 0000000000..53207df769 --- /dev/null +++ b/packages/react-shadcn-ui/package.json @@ -0,0 +1,41 @@ +{ + "name": "@openwebf/react-shadcn-ui", + "version": "0.1.0", + "description": "shadcn/ui style components for WebF applications. This package provides shadcn_ui Flutter widgets wrapped as HTML custom elements for use in WebF.", + "main": "dist/index.cjs", + "module": "dist/index.mjs", + "types": "dist/index.d.mts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + } + }, + "files": ["dist", "README.md"], + "scripts": { + "build": "tsdown" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "@openwebf/react-core-ui": "^0.24.1" + }, + "devDependencies": { + "@openwebf/react-core-ui": "^0.24.1", + "@types/react": "^19.1.0", + "@types/react-dom": "^19.1.2", + "picomatch": "^4.0.2", + "tsdown": "^0.19.0", + "typescript": "^5.8.3" + } +} diff --git a/packages/react-shadcn-ui/src/index.ts b/packages/react-shadcn-ui/src/index.ts new file mode 100644 index 0000000000..a09714db41 --- /dev/null +++ b/packages/react-shadcn-ui/src/index.ts @@ -0,0 +1,82 @@ +/* + * Generated by TSDL, don't edit this file directly. + */ + + +export { FlutterShadcnTheme } from "./lib/src/theme/theme"; +export type { FlutterShadcnThemeElement } from "./lib/src/theme/theme"; +export { FlutterShadcnTooltip } from "./lib/src/components/tooltip"; +export type { FlutterShadcnTooltipElement } from "./lib/src/components/tooltip"; +export { FlutterShadcnToast } from "./lib/src/components/toast"; +export type { FlutterShadcnToastElement } from "./lib/src/components/toast"; +export { FlutterShadcnTimePicker } from "./lib/src/components/time_picker"; +export type { FlutterShadcnTimePickerElement } from "./lib/src/components/time_picker"; +export { FlutterShadcnTextarea } from "./lib/src/components/textarea"; +export type { FlutterShadcnTextareaElement } from "./lib/src/components/textarea"; +export { FlutterShadcnTabs, FlutterShadcnTabsList, FlutterShadcnTabsTrigger, FlutterShadcnTabsContent } from "./lib/src/components/tabs"; +export type { FlutterShadcnTabsElement, FlutterShadcnTabsListElement, FlutterShadcnTabsTriggerElement, FlutterShadcnTabsContentElement } from "./lib/src/components/tabs"; +export { FlutterShadcnTable, FlutterShadcnTableHeader, FlutterShadcnTableBody, FlutterShadcnTableRow, FlutterShadcnTableHead, FlutterShadcnTableCell } from "./lib/src/components/table"; +export type { FlutterShadcnTableElement, FlutterShadcnTableHeaderElement, FlutterShadcnTableBodyElement, FlutterShadcnTableRowElement, FlutterShadcnTableHeadElement, FlutterShadcnTableCellElement } from "./lib/src/components/table"; +export { FlutterShadcnSwitch } from "./lib/src/components/switch"; +export type { FlutterShadcnSwitchElement } from "./lib/src/components/switch"; +export { FlutterShadcnSlider } from "./lib/src/components/slider"; +export type { FlutterShadcnSliderElement } from "./lib/src/components/slider"; +export { FlutterShadcnSkeleton } from "./lib/src/components/skeleton"; +export type { FlutterShadcnSkeletonElement } from "./lib/src/components/skeleton"; +export { FlutterShadcnSheet, FlutterShadcnSheetHeader, FlutterShadcnSheetTitle, FlutterShadcnSheetDescription, FlutterShadcnSheetContent, FlutterShadcnSheetFooter } from "./lib/src/components/sheet"; +export type { FlutterShadcnSheetElement, FlutterShadcnSheetHeaderElement, FlutterShadcnSheetTitleElement, FlutterShadcnSheetDescriptionElement, FlutterShadcnSheetContentElement, FlutterShadcnSheetFooterElement } from "./lib/src/components/sheet"; +export { FlutterShadcnSeparator } from "./lib/src/components/separator"; +export type { FlutterShadcnSeparatorElement } from "./lib/src/components/separator"; +export { FlutterShadcnSelect, FlutterShadcnSelectTrigger, FlutterShadcnSelectContent, FlutterShadcnSelectItem, FlutterShadcnSelectGroup, FlutterShadcnSelectLabel, FlutterShadcnSelectSeparator } from "./lib/src/components/select"; +export type { FlutterShadcnSelectElement, FlutterShadcnSelectTriggerElement, FlutterShadcnSelectContentElement, FlutterShadcnSelectItemElement, FlutterShadcnSelectGroupElement, FlutterShadcnSelectLabelElement, FlutterShadcnSelectSeparatorElement } from "./lib/src/components/select"; +export { FlutterShadcnScrollArea } from "./lib/src/components/scroll_area"; +export type { FlutterShadcnScrollAreaElement } from "./lib/src/components/scroll_area"; +export { FlutterShadcnRadioGroup, FlutterShadcnRadioGroupItem } from "./lib/src/components/radio_group"; +export type { FlutterShadcnRadioGroupElement, FlutterShadcnRadioGroupItemElement } from "./lib/src/components/radio_group"; +export { FlutterShadcnProgress } from "./lib/src/components/progress"; +export type { FlutterShadcnProgressElement } from "./lib/src/components/progress"; +export { FlutterShadcnPopover, FlutterShadcnPopoverTrigger, FlutterShadcnPopoverContent } from "./lib/src/components/popover"; +export type { FlutterShadcnPopoverElement, FlutterShadcnPopoverTriggerElement, FlutterShadcnPopoverContentElement } from "./lib/src/components/popover"; +export { FlutterShadcnInputOtp, FlutterShadcnInputOtpGroup, FlutterShadcnInputOtpSlot, FlutterShadcnInputOtpSeparator } from "./lib/src/components/input_otp"; +export type { FlutterShadcnInputOtpElement, FlutterShadcnInputOtpGroupElement, FlutterShadcnInputOtpSlotElement, FlutterShadcnInputOtpSeparatorElement } from "./lib/src/components/input_otp"; +export { FlutterShadcnInput } from "./lib/src/components/input"; +export type { FlutterShadcnInputElement } from "./lib/src/components/input"; +export { FlutterShadcnImage } from "./lib/src/components/image"; +export type { FlutterShadcnImageElement } from "./lib/src/components/image"; +export { FlutterShadcnIconButton } from "./lib/src/components/icon_button"; +export type { FlutterShadcnIconButtonElement } from "./lib/src/components/icon_button"; +export { FlutterShadcnForm, FlutterShadcnFormField, FlutterShadcnFormLabel, FlutterShadcnFormDescription, FlutterShadcnFormMessage } from "./lib/src/components/form"; +export type { FlutterShadcnFormElement, FlutterShadcnFormFieldElement, FlutterShadcnFormLabelElement, FlutterShadcnFormDescriptionElement, FlutterShadcnFormMessageElement } from "./lib/src/components/form"; +export { FlutterShadcnDropdownMenu, FlutterShadcnDropdownMenuTrigger, FlutterShadcnDropdownMenuContent, FlutterShadcnDropdownMenuItem, FlutterShadcnDropdownMenuSeparator, FlutterShadcnDropdownMenuLabel } from "./lib/src/components/dropdown_menu"; +export type { FlutterShadcnDropdownMenuElement, FlutterShadcnDropdownMenuTriggerElement, FlutterShadcnDropdownMenuContentElement, FlutterShadcnDropdownMenuItemElement, FlutterShadcnDropdownMenuSeparatorElement, FlutterShadcnDropdownMenuLabelElement } from "./lib/src/components/dropdown_menu"; +export { FlutterShadcnDialog, FlutterShadcnDialogHeader, FlutterShadcnDialogTitle, FlutterShadcnDialogDescription, FlutterShadcnDialogContent, FlutterShadcnDialogFooter } from "./lib/src/components/dialog"; +export type { FlutterShadcnDialogElement, FlutterShadcnDialogHeaderElement, FlutterShadcnDialogTitleElement, FlutterShadcnDialogDescriptionElement, FlutterShadcnDialogContentElement, FlutterShadcnDialogFooterElement } from "./lib/src/components/dialog"; +export { FlutterShadcnDatePicker } from "./lib/src/components/date_picker"; +export type { FlutterShadcnDatePickerElement } from "./lib/src/components/date_picker"; +export { FlutterShadcnContextMenu, FlutterShadcnContextMenuTrigger, FlutterShadcnContextMenuContent, FlutterShadcnContextMenuItem, FlutterShadcnContextMenuSeparator, FlutterShadcnContextMenuLabel, FlutterShadcnContextMenuSub, FlutterShadcnContextMenuSubTrigger, FlutterShadcnContextMenuSubContent, FlutterShadcnContextMenuCheckboxItem, FlutterShadcnContextMenuRadioGroup, FlutterShadcnContextMenuRadioItem } from "./lib/src/components/context_menu"; +export type { FlutterShadcnContextMenuElement, FlutterShadcnContextMenuTriggerElement, FlutterShadcnContextMenuContentElement, FlutterShadcnContextMenuItemElement, FlutterShadcnContextMenuSeparatorElement, FlutterShadcnContextMenuLabelElement, FlutterShadcnContextMenuSubElement, FlutterShadcnContextMenuSubTriggerElement, FlutterShadcnContextMenuSubContentElement, FlutterShadcnContextMenuCheckboxItemElement, FlutterShadcnContextMenuRadioGroupElement, FlutterShadcnContextMenuRadioItemElement } from "./lib/src/components/context_menu"; +export { FlutterShadcnMenubar, FlutterShadcnMenubarMenu, FlutterShadcnMenubarTrigger, FlutterShadcnMenubarContent, FlutterShadcnMenubarItem, FlutterShadcnMenubarSeparator, FlutterShadcnMenubarLabel, FlutterShadcnMenubarSub, FlutterShadcnMenubarSubTrigger, FlutterShadcnMenubarSubContent, FlutterShadcnMenubarCheckboxItem, FlutterShadcnMenubarRadioGroup, FlutterShadcnMenubarRadioItem } from "./lib/src/components/menubar"; +export type { FlutterShadcnMenubarElement, FlutterShadcnMenubarMenuElement, FlutterShadcnMenubarTriggerElement, FlutterShadcnMenubarContentElement, FlutterShadcnMenubarItemElement, FlutterShadcnMenubarSeparatorElement, FlutterShadcnMenubarLabelElement, FlutterShadcnMenubarSubElement, FlutterShadcnMenubarSubTriggerElement, FlutterShadcnMenubarSubContentElement, FlutterShadcnMenubarCheckboxItemElement, FlutterShadcnMenubarRadioGroupElement, FlutterShadcnMenubarRadioItemElement } from "./lib/src/components/menubar"; +export { FlutterShadcnCombobox, FlutterShadcnComboboxItem } from "./lib/src/components/combobox"; +export type { FlutterShadcnComboboxElement, FlutterShadcnComboboxItemElement } from "./lib/src/components/combobox"; +export { FlutterShadcnCollapsible, FlutterShadcnCollapsibleTrigger, FlutterShadcnCollapsibleContent } from "./lib/src/components/collapsible"; +export type { FlutterShadcnCollapsibleElement, FlutterShadcnCollapsibleTriggerElement, FlutterShadcnCollapsibleContentElement } from "./lib/src/components/collapsible"; +export { FlutterShadcnCheckbox } from "./lib/src/components/checkbox"; +export type { FlutterShadcnCheckboxElement } from "./lib/src/components/checkbox"; +export { FlutterShadcnCard, FlutterShadcnCardHeader, FlutterShadcnCardTitle, FlutterShadcnCardDescription, FlutterShadcnCardContent, FlutterShadcnCardFooter } from "./lib/src/components/card"; +export type { FlutterShadcnCardElement, FlutterShadcnCardHeaderElement, FlutterShadcnCardTitleElement, FlutterShadcnCardDescriptionElement, FlutterShadcnCardContentElement, FlutterShadcnCardFooterElement } from "./lib/src/components/card"; +export { FlutterShadcnCalendar } from "./lib/src/components/calendar"; +export type { FlutterShadcnCalendarElement } from "./lib/src/components/calendar"; +export { FlutterShadcnButton } from "./lib/src/components/button"; +export type { FlutterShadcnButtonElement } from "./lib/src/components/button"; +export { FlutterShadcnBreadcrumb, FlutterShadcnBreadcrumbList, FlutterShadcnBreadcrumbItem, FlutterShadcnBreadcrumbLink, FlutterShadcnBreadcrumbPage, FlutterShadcnBreadcrumbSeparator, FlutterShadcnBreadcrumbEllipsis, FlutterShadcnBreadcrumbDropdown, FlutterShadcnBreadcrumbDropdownItem } from "./lib/src/components/breadcrumb"; +export type { FlutterShadcnBreadcrumbElement, FlutterShadcnBreadcrumbListElement, FlutterShadcnBreadcrumbItemElement, FlutterShadcnBreadcrumbLinkElement, FlutterShadcnBreadcrumbPageElement, FlutterShadcnBreadcrumbSeparatorElement, FlutterShadcnBreadcrumbEllipsisElement, FlutterShadcnBreadcrumbDropdownElement, FlutterShadcnBreadcrumbDropdownItemElement } from "./lib/src/components/breadcrumb"; +export { FlutterShadcnBadge } from "./lib/src/components/badge"; +export type { FlutterShadcnBadgeElement } from "./lib/src/components/badge"; +export { FlutterShadcnAvatar } from "./lib/src/components/avatar"; +export type { FlutterShadcnAvatarElement } from "./lib/src/components/avatar"; +export { FlutterShadcnAlert, FlutterShadcnAlertTitle, FlutterShadcnAlertDescription } from "./lib/src/components/alert"; +export type { FlutterShadcnAlertElement, FlutterShadcnAlertTitleElement, FlutterShadcnAlertDescriptionElement } from "./lib/src/components/alert"; +export { FlutterShadcnAccordion, FlutterShadcnAccordionItem, FlutterShadcnAccordionTrigger, FlutterShadcnAccordionContent } from "./lib/src/components/accordion"; +export type { FlutterShadcnAccordionElement, FlutterShadcnAccordionItemElement, FlutterShadcnAccordionTriggerElement, FlutterShadcnAccordionContentElement } from "./lib/src/components/accordion"; +export * from './types'; diff --git a/packages/react-shadcn-ui/src/lib/src/components/accordion.tsx b/packages/react-shadcn-ui/src/lib/src/components/accordion.tsx new file mode 100644 index 0000000000..d69c9584ad --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/accordion.tsx @@ -0,0 +1,267 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnAccordionProps { + /** + * Selection type. + * - 'single': Only one item can be expanded + * - 'multiple': Multiple items can be expanded + * Default: 'single' + */ + type?: string; + /** + * Currently expanded item(s) value(s). + * For single type: string, for multiple type: comma-separated string + */ + value?: string; + /** + * Allow collapsing all items in single mode. + * Default: true + */ + collapsible?: boolean; + /** + * change event handler + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAccordionElement extends WebFElementWithMethods<{ +}> { + /** Selection type. */ + type?: string; + /** Currently expanded item(s) value(s). */ + value?: string; + /** Allow collapsing all items in single mode. */ + collapsible?: boolean; +} +/** + * Properties for +A collapsible accordion component. +@example +```html + + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAccordion = createWebFComponent({ + tagName: 'flutter-shadcn-accordion', + displayName: 'FlutterShadcnAccordion', + // Map props to attributes + attributeProps: [ + 'type', + 'value', + 'collapsible', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnAccordionItemProps { + /** + * value property + */ + value: string; + /** + * disabled property + * @default undefined + */ + disabled?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAccordionItemElement extends WebFElementWithMethods<{ +}> { + value: string; + disabled?: boolean; +} +/** + * FlutterShadcnAccordionItem - WebF FlutterShadcnAccordionItem component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAccordionItem = createWebFComponent({ + tagName: 'flutter-shadcn-accordion-item', + displayName: 'FlutterShadcnAccordionItem', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnAccordionTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAccordionTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnAccordionTrigger - WebF FlutterShadcnAccordionTrigger component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAccordionTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-accordion-trigger', + displayName: 'FlutterShadcnAccordionTrigger', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnAccordionContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAccordionContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnAccordionContent - WebF FlutterShadcnAccordionContent component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAccordionContent = createWebFComponent({ + tagName: 'flutter-shadcn-accordion-content', + displayName: 'FlutterShadcnAccordionContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/alert.tsx b/packages/react-shadcn-ui/src/lib/src/components/alert.tsx new file mode 100644 index 0000000000..69729f6eb8 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/alert.tsx @@ -0,0 +1,185 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnAlertProps { + /** + * Visual variant of the alert. + * - 'default': Standard informational alert + * - 'destructive': Red destructive/error alert + * Default: 'default' + */ + variant?: string; + /** + * Icon name to display in the alert. + */ + icon?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAlertElement extends WebFElementWithMethods<{ +}> { + /** Visual variant of the alert. */ + variant?: string; + /** Icon name to display in the alert. */ + icon?: string; +} +/** + * Properties for +An alert component for displaying important messages. +@example +```html + + Heads up! + + You can add components to your app using the CLI. + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAlert = createWebFComponent({ + tagName: 'flutter-shadcn-alert', + displayName: 'FlutterShadcnAlert', + // Map props to attributes + attributeProps: [ + 'variant', + 'icon', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnAlertTitleProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAlertTitleElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Title slot for the alert. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAlertTitle = createWebFComponent({ + tagName: 'flutter-shadcn-alert-title', + displayName: 'FlutterShadcnAlertTitle', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnAlertDescriptionProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAlertDescriptionElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Description slot for the alert. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAlertDescription = createWebFComponent({ + tagName: 'flutter-shadcn-alert-description', + displayName: 'FlutterShadcnAlertDescription', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/avatar.tsx b/packages/react-shadcn-ui/src/lib/src/components/avatar.tsx new file mode 100644 index 0000000000..ff8864483f --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/avatar.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnAvatarProps { + /** + * URL of the avatar image. + */ + src?: string; + /** + * Alt text for the image. + */ + alt?: string; + /** + * Fallback text/initials when image fails to load or is not provided. + */ + fallback?: string; + /** + * Size of the avatar in pixels. + * Default: 40 + */ + size?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnAvatarElement extends WebFElementWithMethods<{ +}> { + /** URL of the avatar image. */ + src?: string; + /** Alt text for the image. */ + alt?: string; + /** Fallback text/initials when image fails to load or is not provided. */ + fallback?: string; + /** Size of the avatar in pixels. */ + size?: string; +} +/** + * Properties for +An avatar component for displaying user images or initials. +@example +```html + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnAvatar = createWebFComponent({ + tagName: 'flutter-shadcn-avatar', + displayName: 'FlutterShadcnAvatar', + // Map props to attributes + attributeProps: [ + 'src', + 'alt', + 'fallback', + 'size', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/badge.tsx b/packages/react-shadcn-ui/src/lib/src/components/badge.tsx new file mode 100644 index 0000000000..fafc0e1697 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/badge.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnBadgeProps { + /** + * Visual variant of the badge. + * - 'default': Primary filled badge + * - 'secondary': Secondary muted badge + * - 'destructive': Red destructive badge + * - 'outline': Bordered outline badge + * Default: 'default' + */ + variant?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBadgeElement extends WebFElementWithMethods<{ +}> { + /** Visual variant of the badge. */ + variant?: string; +} +/** + * Properties for +A small badge component for displaying labels or counts. +@example +```html +New +Error +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBadge = createWebFComponent({ + tagName: 'flutter-shadcn-badge', + displayName: 'FlutterShadcnBadge', + // Map props to attributes + attributeProps: [ + 'variant', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/breadcrumb.tsx b/packages/react-shadcn-ui/src/lib/src/components/breadcrumb.tsx new file mode 100644 index 0000000000..f8214d490e --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/breadcrumb.tsx @@ -0,0 +1,572 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnBreadcrumbProps { + /** + * Spacing between breadcrumb items. + * @default 10 + */ + spacing?: number; + /** + * Custom separator between items. + * Predefined values: 'slash', '/', 'arrow', '>', 'dash', '-', 'dot', '.', 'chevron' + * Or any custom string to use as separator text. + * @default chevron icon + */ + separator?: 'slash' | 'arrow' | 'dash' | 'dot' | 'chevron' | any; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbElement extends WebFElementWithMethods<{ +}> { + /** Spacing between breadcrumb items. */ + spacing?: number; + /** Custom separator between items. */ + separator?: 'slash' | 'arrow' | 'dash' | 'dot' | 'chevron' | any; +} +/** + * Properties for +A breadcrumb navigation component that displays the current page location +within a navigational hierarchy. +@example +```html + + + Home + + + Components + + + Breadcrumb + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumb = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb', + displayName: 'FlutterShadcnBreadcrumb', + // Map props to attributes + attributeProps: [ + 'spacing', + 'separator', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbListProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbListElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Container for breadcrumb items (for backwards compatibility). + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbList = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-list', + displayName: 'FlutterShadcnBreadcrumbList', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbItemProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbItemElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Individual breadcrumb item container. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbItem = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-item', + displayName: 'FlutterShadcnBreadcrumbItem', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbLinkProps { + /** + * Link destination URL. + */ + href?: string; + /** + * Fired when link is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbLinkElement extends WebFElementWithMethods<{ +}> { + /** Link destination URL. */ + href?: string; +} +/** + * Properties for +Clickable breadcrumb link with hover effects. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbLink = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-link', + displayName: 'FlutterShadcnBreadcrumbLink', + // Map props to attributes + attributeProps: [ + 'href', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbPageProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbPageElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Current page indicator (non-clickable, highlighted text). + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbPage = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-page', + displayName: 'FlutterShadcnBreadcrumbPage', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbSeparatorProps { + /** + * Size of the separator icon. + * @default 14 + */ + size?: number; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbSeparatorElement extends WebFElementWithMethods<{ +}> { + /** Size of the separator icon. */ + size?: number; +} +/** + * Properties for +Separator between breadcrumb items (chevron icon by default). + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-separator', + displayName: 'FlutterShadcnBreadcrumbSeparator', + // Map props to attributes + attributeProps: [ + 'size', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbEllipsisProps { + /** + * Size of the ellipsis icon. + * @default 16 + */ + size?: number; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbEllipsisElement extends WebFElementWithMethods<{ +}> { + /** Size of the ellipsis icon. */ + size?: number; +} +/** + * Properties for +Ellipsis indicator for collapsed/hidden breadcrumb sections. +@example +```html + + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbEllipsis = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-ellipsis', + displayName: 'FlutterShadcnBreadcrumbEllipsis', + // Map props to attributes + attributeProps: [ + 'size', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbDropdownProps { + /** + * Whether to show the dropdown arrow icon. + * @default true + */ + showArrow?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbDropdownElement extends WebFElementWithMethods<{ +}> { + /** Whether to show the dropdown arrow icon. */ + showArrow?: boolean; +} +/** + * Properties for +Dropdown menu for showing collapsed breadcrumb items. +@example +```html + + + Documentation + Themes + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbDropdown = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-dropdown', + displayName: 'FlutterShadcnBreadcrumbDropdown', + // Map props to attributes + attributeProps: [ + 'showArrow', + ], + // Convert prop names to attribute names if needed + attributeMap: { + showArrow: 'show-arrow', + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnBreadcrumbDropdownItemProps { + /** + * Fired when dropdown item is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnBreadcrumbDropdownItemElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Individual item in a breadcrumb dropdown menu. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnBreadcrumbDropdownItem = createWebFComponent({ + tagName: 'flutter-shadcn-breadcrumb-dropdown-item', + displayName: 'FlutterShadcnBreadcrumbDropdownItem', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/button.tsx b/packages/react-shadcn-ui/src/lib/src/components/button.tsx new file mode 100644 index 0000000000..611568877c --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/button.tsx @@ -0,0 +1,119 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnButtonProps { + /** + * Visual variant of the button. + * - 'default': Primary filled button + * - 'secondary': Secondary muted button + * - 'destructive': Red destructive action button + * - 'outline': Bordered outline button + * - 'ghost': Transparent with hover effect + * - 'link': Text link style button + * Default: 'default' + */ + variant?: string; + /** + * Size of the button. + * - 'default': Standard size + * - 'sm': Small size + * - 'lg': Large size + * - 'icon': Square icon-only button + * Default: 'default' + */ + size?: string; + /** + * Disable button interactions. + */ + disabled?: boolean; + /** + * Show loading spinner and disable interactions. + */ + loading?: boolean; + /** + * Icon name to show before the button text. + */ + icon?: string; + /** + * Fired when the button is pressed (not emitted when disabled or loading). + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnButtonElement extends WebFElementWithMethods<{ +}> { + /** Visual variant of the button. */ + variant?: string; + /** Size of the button. */ + size?: string; + /** Disable button interactions. */ + disabled?: boolean; + /** Show loading spinner and disable interactions. */ + loading?: boolean; + /** Icon name to show before the button text. */ + icon?: string; +} +/** + * Properties for +A versatile button component with multiple variants and sizes. +@example +```html + + Click me + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnButton = createWebFComponent({ + tagName: 'flutter-shadcn-button', + displayName: 'FlutterShadcnButton', + // Map props to attributes + attributeProps: [ + 'variant', + 'size', + 'disabled', + 'loading', + 'icon', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/calendar.tsx b/packages/react-shadcn-ui/src/lib/src/components/calendar.tsx new file mode 100644 index 0000000000..08577dea4c --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/calendar.tsx @@ -0,0 +1,210 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +/** + * Detail for calendar change event. + */ +interface FlutterShadcnCalendarChangeEventDetail { + /** + * The selected value. + * - For single mode: ISO date string (YYYY-MM-DD) or null + * - For multiple mode: Comma-separated ISO date strings + * - For range mode: Comma-separated start and end dates + */ + value: string | null; +} +export interface FlutterShadcnCalendarProps { + /** + * Selection mode. + * - 'single': Select one date + * - 'multiple': Select multiple dates (value is comma-separated) + * - 'range': Select a date range (value is start,end) + * @default 'single' + */ + mode?: 'single' | 'multiple' | 'range'; + /** + * Selected date(s) in ISO format (YYYY-MM-DD). + * - For single: '2024-01-15' + * - For multiple: '2024-01-15,2024-01-20,2024-01-25' + * - For range: '2024-01-15,2024-01-20' (start,end) + */ + value?: string; + /** + * Disable the calendar. + */ + disabled?: boolean; + /** + * Minimum selectable date (YYYY-MM-DD). + */ + min?: string; + /** + * Maximum selectable date (YYYY-MM-DD). + */ + max?: string; + /** + * Caption layout style. + * - 'label': Default label style + * - 'dropdown': Both month and year dropdowns + * - 'dropdown-months': Month dropdown only + * - 'dropdown-years': Year dropdown only + * @default 'label' + */ + captionLayout?: 'label' | 'dropdown' | 'dropdown-months' | 'dropdown-years'; + /** + * Hide the navigation arrows (prev/next month). + * @default false + */ + hideNavigation?: boolean; + /** + * Show week numbers column. + * @default false + */ + showWeekNumbers?: boolean; + /** + * Show days from adjacent months. + * @default true + */ + showOutsideDays?: boolean; + /** + * Always display 6 weeks for consistent height. + * @default false + */ + fixedWeeks?: boolean; + /** + * Hide the weekday name headers (Mon, Tue, etc.). + * @default false + */ + hideWeekdayNames?: boolean; + /** + * Number of months to display simultaneously. + * @default 1 + */ + numberOfMonths?: number; + /** + * Allow deselecting a selected date by clicking it again. + * Only applies to 'single' selection mode. + * @default false + */ + allowDeselection?: boolean; + /** + * Fired when date selection changes. Detail contains the selected value. + */ + onChange?: (event: CustomEvent) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCalendarElement extends WebFElementWithMethods<{ +}> { + /** Selection mode. */ + mode?: 'single' | 'multiple' | 'range'; + /** Selected date(s) in ISO format (YYYY-MM-DD). */ + value?: string; + /** Disable the calendar. */ + disabled?: boolean; + /** Minimum selectable date (YYYY-MM-DD). */ + min?: string; + /** Maximum selectable date (YYYY-MM-DD). */ + max?: string; + /** Caption layout style. */ + captionLayout?: 'label' | 'dropdown' | 'dropdown-months' | 'dropdown-years'; + /** Hide the navigation arrows (prev/next month). */ + hideNavigation?: boolean; + /** Show week numbers column. */ + showWeekNumbers?: boolean; + /** Show days from adjacent months. */ + showOutsideDays?: boolean; + /** Always display 6 weeks for consistent height. */ + fixedWeeks?: boolean; + /** Hide the weekday name headers (Mon, Tue, etc.). */ + hideWeekdayNames?: boolean; + /** Number of months to display simultaneously. */ + numberOfMonths?: number; + /** Allow deselecting a selected date by clicking it again. */ + allowDeselection?: boolean; +} +/** + * Properties for +A calendar component for date selection with support for single, multiple, and range modes. +@example +```html + + + + + + + + + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCalendar = createWebFComponent({ + tagName: 'flutter-shadcn-calendar', + displayName: 'FlutterShadcnCalendar', + // Map props to attributes + attributeProps: [ + 'mode', + 'value', + 'disabled', + 'min', + 'max', + 'captionLayout', + 'hideNavigation', + 'showWeekNumbers', + 'showOutsideDays', + 'fixedWeeks', + 'hideWeekdayNames', + 'numberOfMonths', + 'allowDeselection', + ], + // Convert prop names to attribute names if needed + attributeMap: { + captionLayout: 'caption-layout', + hideNavigation: 'hide-navigation', + showWeekNumbers: 'show-week-numbers', + showOutsideDays: 'show-outside-days', + fixedWeeks: 'fixed-weeks', + hideWeekdayNames: 'hide-weekday-names', + numberOfMonths: 'number-of-months', + allowDeselection: 'allow-deselection', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/card.tsx b/packages/react-shadcn-ui/src/lib/src/components/card.tsx new file mode 100644 index 0000000000..ca48b16833 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/card.tsx @@ -0,0 +1,330 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnCardProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +A container card with optional header, content, and footer slots. +@example +```html + + + Card Title + Card description here. + + +

Card content goes here.

+
+ + Action + +
+``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCard = createWebFComponent({ + tagName: 'flutter-shadcn-card', + displayName: 'FlutterShadcnCard', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCardHeaderProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardHeaderElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Header slot for the card. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCardHeader = createWebFComponent({ + tagName: 'flutter-shadcn-card-header', + displayName: 'FlutterShadcnCardHeader', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCardTitleProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardTitleElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Title slot within card header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCardTitle = createWebFComponent({ + tagName: 'flutter-shadcn-card-title', + displayName: 'FlutterShadcnCardTitle', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCardDescriptionProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardDescriptionElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Description slot within card header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCardDescription = createWebFComponent({ + tagName: 'flutter-shadcn-card-description', + displayName: 'FlutterShadcnCardDescription', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCardContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Main content slot for the card. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCardContent = createWebFComponent({ + tagName: 'flutter-shadcn-card-content', + displayName: 'FlutterShadcnCardContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCardFooterProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCardFooterElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Footer slot for the card. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCardFooter = createWebFComponent({ + tagName: 'flutter-shadcn-card-footer', + displayName: 'FlutterShadcnCardFooter', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/checkbox.tsx b/packages/react-shadcn-ui/src/lib/src/components/checkbox.tsx new file mode 100644 index 0000000000..7b23af118a --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/checkbox.tsx @@ -0,0 +1,96 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnCheckboxProps { + /** + * Whether the checkbox is checked. + */ + checked?: boolean; + /** + * Disable the checkbox. + */ + disabled?: boolean; + /** + * Show indeterminate state (neither checked nor unchecked). + */ + indeterminate?: boolean; + /** + * Fired when the checked state changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCheckboxElement extends WebFElementWithMethods<{ +}> { + /** Whether the checkbox is checked. */ + checked?: boolean; + /** Disable the checkbox. */ + disabled?: boolean; + /** Show indeterminate state (neither checked nor unchecked). */ + indeterminate?: boolean; +} +/** + * Properties for +A checkbox control for boolean input. +@example +```html + + Accept terms and conditions + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCheckbox = createWebFComponent({ + tagName: 'flutter-shadcn-checkbox', + displayName: 'FlutterShadcnCheckbox', + // Map props to attributes + attributeProps: [ + 'checked', + 'disabled', + 'indeterminate', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/collapsible.tsx b/packages/react-shadcn-ui/src/lib/src/components/collapsible.tsx new file mode 100644 index 0000000000..e66afc6cea --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/collapsible.tsx @@ -0,0 +1,193 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnCollapsibleProps { + /** + * Whether the section is expanded. + */ + open?: boolean; + /** + * Disable the collapsible. + */ + disabled?: boolean; + /** + * Fired when open state changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCollapsibleElement extends WebFElementWithMethods<{ +}> { + /** Whether the section is expanded. */ + open?: boolean; + /** Disable the collapsible. */ + disabled?: boolean; +} +/** + * Properties for +A collapsible section. +@example +```html + + + Toggle + + + Hidden content here + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCollapsible = createWebFComponent({ + tagName: 'flutter-shadcn-collapsible', + displayName: 'FlutterShadcnCollapsible', + // Map props to attributes + attributeProps: [ + 'open', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCollapsibleTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCollapsibleTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnCollapsibleTrigger - WebF FlutterShadcnCollapsibleTrigger component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCollapsibleTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-collapsible-trigger', + displayName: 'FlutterShadcnCollapsibleTrigger', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnCollapsibleContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnCollapsibleContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnCollapsibleContent - WebF FlutterShadcnCollapsibleContent component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCollapsibleContent = createWebFComponent({ + tagName: 'flutter-shadcn-collapsible-content', + displayName: 'FlutterShadcnCollapsibleContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/combobox.tsx b/packages/react-shadcn-ui/src/lib/src/components/combobox.tsx new file mode 100644 index 0000000000..d24fac8187 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/combobox.tsx @@ -0,0 +1,200 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnComboboxProps { + /** + * Currently selected value. + */ + value?: string; + /** + * Placeholder text when no value is selected. + */ + placeholder?: string; + /** + * Placeholder for the search input. + */ + searchPlaceholder?: string; + /** + * Text shown when no results match the search. + */ + emptyText?: string; + /** + * Disable the combobox. + */ + disabled?: boolean; + /** + * Allow clearing the selection. + */ + clearable?: boolean; + /** + * Fired when selection changes. + */ + onChange?: (event: Event) => void; + /** + * Fired when search query changes. + */ + onSearch?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnComboboxElement extends WebFElementWithMethods<{ +}> { + /** Currently selected value. */ + value?: string; + /** Placeholder text when no value is selected. */ + placeholder?: string; + /** Placeholder for the search input. */ + searchPlaceholder?: string; + /** Text shown when no results match the search. */ + emptyText?: string; + /** Disable the combobox. */ + disabled?: boolean; + /** Allow clearing the selection. */ + clearable?: boolean; +} +/** + * Properties for +A searchable dropdown with autocomplete functionality. +@example +```html + + React + Vue + Angular + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnCombobox = createWebFComponent({ + tagName: 'flutter-shadcn-combobox', + displayName: 'FlutterShadcnCombobox', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'searchPlaceholder', + 'emptyText', + 'disabled', + 'clearable', + ], + // Convert prop names to attribute names if needed + attributeMap: { + searchPlaceholder: 'search-placeholder', + emptyText: 'empty-text', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onSearch', + eventName: 'search', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnComboboxItemProps { + /** + * Value of this option. + */ + value: string; + /** + * Disable this specific option. + */ + disabled?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnComboboxItemElement extends WebFElementWithMethods<{ +}> { + /** Value of this option. */ + value: string; + /** Disable this specific option. */ + disabled?: boolean; +} +/** + * Properties for +Individual combobox option. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnComboboxItem = createWebFComponent({ + tagName: 'flutter-shadcn-combobox-item', + displayName: 'FlutterShadcnComboboxItem', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/context_menu.tsx b/packages/react-shadcn-ui/src/lib/src/components/context_menu.tsx new file mode 100644 index 0000000000..b3d9a4bada --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/context_menu.tsx @@ -0,0 +1,832 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +interface FlutterShadcnContextMenuRadioGroupChangeEventDetail { + value: string | null; +} +export interface FlutterShadcnContextMenuProps { + /** + * Whether the menu is open. + * + * This value is updated automatically when the native menu opens/closes. + * Setting it to `false` will close the menu. + */ + open?: boolean; + /** + * Fired when menu opens. + */ + onOpen?: (event: Event) => void; + /** + * Fired when menu closes. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuElement extends WebFElementWithMethods<{ +}> { + /** Whether the menu is open. */ + open?: boolean; +} +/** + * Properties for +A context menu that appears on right-click. +@example +```html + + +
Right click here
+
+ + Cut + Copy + Paste + +
+``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenu = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu', + displayName: 'FlutterShadcnContextMenu', + // Map props to attributes + attributeProps: [ + 'open', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onOpen', + eventName: 'open', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-trigger', + displayName: 'FlutterShadcnContextMenuTrigger', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuContent = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-content', + displayName: 'FlutterShadcnContextMenuContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * Keyboard shortcut to display (e.g., "⌘Z", "Ctrl+C"). + * + * When the context menu is open, matching key presses will trigger the + * item's `click` handler. + */ + shortcut?: string; + /** + * Whether to use inset styling (adds left padding for alignment with checkbox/radio items). + */ + inset?: boolean; + /** + * Fired when the item is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** Keyboard shortcut to display (e.g., "⌘Z", "Ctrl+C"). */ + shortcut?: string; + /** Whether to use inset styling (adds left padding for alignment with checkbox/radio items). */ + inset?: boolean; +} +/** + * Properties for + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuItem = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-item', + displayName: 'FlutterShadcnContextMenuItem', + // Map props to attributes + attributeProps: [ + 'disabled', + 'shortcut', + 'inset', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuSeparatorProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuSeparatorElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-separator', + displayName: 'FlutterShadcnContextMenuSeparator', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuLabelProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuLabelElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +A label/header for grouping context menu items. +@example +```html +People +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuLabel = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-label', + displayName: 'FlutterShadcnContextMenuLabel', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuSubProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuSubElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +A container for nested submenu items. +Submenus open on hover (mouse) and can be toggled by tap/click. +@example +```html + + More Tools + + Save Page As... + Create Shortcut... + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuSub = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-sub', + displayName: 'FlutterShadcnContextMenuSub', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuSubTriggerProps { + /** + * Whether the submenu trigger is disabled. + */ + disabled?: boolean; + /** + * Whether to use inset styling (adds left padding for alignment). + */ + inset?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuSubTriggerElement extends WebFElementWithMethods<{ +}> { + /** Whether the submenu trigger is disabled. */ + disabled?: boolean; + /** Whether to use inset styling (adds left padding for alignment). */ + inset?: boolean; +} +/** + * Properties for +The trigger element for a submenu. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuSubTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-sub-trigger', + displayName: 'FlutterShadcnContextMenuSubTrigger', + // Map props to attributes + attributeProps: [ + 'disabled', + 'inset', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuSubContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuSubContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Container for submenu items. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuSubContent = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-sub-content', + displayName: 'FlutterShadcnContextMenuSubContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuCheckboxItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * Whether the checkbox is checked. + */ + checked?: boolean; + /** + * Keyboard shortcut to display (e.g., "⌘B"). + */ + shortcut?: string; + /** + * Fired when the checked state changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuCheckboxItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** Whether the checkbox is checked. */ + checked?: boolean; + /** Keyboard shortcut to display (e.g., "⌘B"). */ + shortcut?: string; +} +/** + * Properties for +A menu item with a checkbox indicator. +@example +```html + + Show Bookmarks Bar + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuCheckboxItem = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-checkbox-item', + displayName: 'FlutterShadcnContextMenuCheckboxItem', + // Map props to attributes + attributeProps: [ + 'disabled', + 'checked', + 'shortcut', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuRadioGroupProps { + /** + * The value of the currently selected radio item. + */ + value?: string; + /** + * Fired when the selected value changes. + */ + onChange?: (event: CustomEvent) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuRadioGroupElement extends WebFElementWithMethods<{ +}> { + /** The value of the currently selected radio item. */ + value?: string; +} +/** + * Properties for +A group of radio items where only one can be selected. +@example +```html + + People + + Pedro Duarte + Colm Tuite + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuRadioGroup = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-radio-group', + displayName: 'FlutterShadcnContextMenuRadioGroup', + // Map props to attributes + attributeProps: [ + 'value', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnContextMenuRadioItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * The value of this radio item. + */ + value?: string; + /** + * Keyboard shortcut to display. + */ + shortcut?: string; + /** + * Fired when the item is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnContextMenuRadioItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** The value of this radio item. */ + value?: string; + /** Keyboard shortcut to display. */ + shortcut?: string; +} +/** + * Properties for +A radio-style menu item within a radio group. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnContextMenuRadioItem = createWebFComponent({ + tagName: 'flutter-shadcn-context-menu-radio-item', + displayName: 'FlutterShadcnContextMenuRadioItem', + // Map props to attributes + attributeProps: [ + 'disabled', + 'value', + 'shortcut', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/date_picker.tsx b/packages/react-shadcn-ui/src/lib/src/components/date_picker.tsx new file mode 100644 index 0000000000..64acd6ce13 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/date_picker.tsx @@ -0,0 +1,112 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +/** + * Detail for date picker change event. + */ +interface FlutterShadcnDatePickerChangeEventDetail { + /** + * The selected date in ISO format (YYYY-MM-DD). + */ + value: string; +} +export interface FlutterShadcnDatePickerProps { + /** + * Selected date in ISO format (YYYY-MM-DD). + */ + value?: string; + /** + * Placeholder text when no date is selected. + */ + placeholder?: string; + /** + * Disable the picker. + */ + disabled?: boolean; + /** + * Date format for display. + * Default: 'yyyy-MM-dd' + */ + format?: string; + /** + * Fired when date selection changes. Detail contains the selected value. + */ + onChange?: (event: CustomEvent) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDatePickerElement extends WebFElementWithMethods<{ +}> { + /** Selected date in ISO format (YYYY-MM-DD). */ + value?: string; + /** Placeholder text when no date is selected. */ + placeholder?: string; + /** Disable the picker. */ + disabled?: boolean; + /** Date format for display. */ + format?: string; +} +/** + * Properties for +A date picker with a popover calendar. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDatePicker = createWebFComponent({ + tagName: 'flutter-shadcn-date-picker', + displayName: 'FlutterShadcnDatePicker', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'disabled', + 'format', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/dialog.tsx b/packages/react-shadcn-ui/src/lib/src/components/dialog.tsx new file mode 100644 index 0000000000..4654d2f30a --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/dialog.tsx @@ -0,0 +1,371 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnDialogProps { + /** + * Whether the dialog is open. + */ + open?: boolean; + /** + * Close when clicking outside the dialog. + * Default: true + */ + closeOnOutsideClick?: boolean; + /** + * Fired when dialog opens. + */ + onOpen?: (event: Event) => void; + /** + * Fired when dialog closes. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogElement extends WebFElementWithMethods<{ +}> { + /** Whether the dialog is open. */ + open?: boolean; + /** Close when clicking outside the dialog. */ + closeOnOutsideClick?: boolean; +} +/** + * Properties for +A modal dialog component. +@example +```html + + + Are you sure? + + This action cannot be undone. + + + + Dialog content here. + + + Cancel + Continue + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialog = createWebFComponent({ + tagName: 'flutter-shadcn-dialog', + displayName: 'FlutterShadcnDialog', + // Map props to attributes + attributeProps: [ + 'open', + 'closeOnOutsideClick', + ], + // Convert prop names to attribute names if needed + attributeMap: { + closeOnOutsideClick: 'close-on-outside-click', + }, + // Event handlers + events: [ + { + propName: 'onOpen', + eventName: 'open', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDialogHeaderProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogHeaderElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Header slot for dialog. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialogHeader = createWebFComponent({ + tagName: 'flutter-shadcn-dialog-header', + displayName: 'FlutterShadcnDialogHeader', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDialogTitleProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogTitleElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Title within dialog header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialogTitle = createWebFComponent({ + tagName: 'flutter-shadcn-dialog-title', + displayName: 'FlutterShadcnDialogTitle', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDialogDescriptionProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogDescriptionElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Description within dialog header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialogDescription = createWebFComponent({ + tagName: 'flutter-shadcn-dialog-description', + displayName: 'FlutterShadcnDialogDescription', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDialogContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Main content slot for dialog. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialogContent = createWebFComponent({ + tagName: 'flutter-shadcn-dialog-content', + displayName: 'FlutterShadcnDialogContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDialogFooterProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDialogFooterElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Footer slot for dialog actions. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDialogFooter = createWebFComponent({ + tagName: 'flutter-shadcn-dialog-footer', + displayName: 'FlutterShadcnDialogFooter', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/dropdown_menu.tsx b/packages/react-shadcn-ui/src/lib/src/components/dropdown_menu.tsx new file mode 100644 index 0000000000..9e0cd374e3 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/dropdown_menu.tsx @@ -0,0 +1,376 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnDropdownMenuProps { + /** + * Whether the menu is open. + */ + open?: boolean; + /** + * Fired when menu opens. + */ + onOpen?: (event: Event) => void; + /** + * Fired when menu closes. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuElement extends WebFElementWithMethods<{ +}> { + /** Whether the menu is open. */ + open?: boolean; +} +/** + * Properties for +A dropdown menu component. +@example +```html + + + Open Menu + + + Profile + Settings + + Logout + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenu = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu', + displayName: 'FlutterShadcnDropdownMenu', + // Map props to attributes + attributeProps: [ + 'open', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onOpen', + eventName: 'open', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDropdownMenuTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Trigger element for the menu. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenuTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu-trigger', + displayName: 'FlutterShadcnDropdownMenuTrigger', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDropdownMenuContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Container for menu items. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenuContent = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu-content', + displayName: 'FlutterShadcnDropdownMenuContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDropdownMenuItemProps { + /** + * Disable this menu item. + */ + disabled?: boolean; + /** + * Fired when item is selected. + */ + onSelect?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuItemElement extends WebFElementWithMethods<{ +}> { + /** Disable this menu item. */ + disabled?: boolean; +} +/** + * Properties for +Individual menu item. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenuItem = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu-item', + displayName: 'FlutterShadcnDropdownMenuItem', + // Map props to attributes + attributeProps: [ + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onSelect', + eventName: 'select', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDropdownMenuSeparatorProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuSeparatorElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Visual separator between items. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenuSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu-separator', + displayName: 'FlutterShadcnDropdownMenuSeparator', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnDropdownMenuLabelProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnDropdownMenuLabelElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Label/header for a group of items. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnDropdownMenuLabel = createWebFComponent({ + tagName: 'flutter-shadcn-dropdown-menu-label', + displayName: 'FlutterShadcnDropdownMenuLabel', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/form.tsx b/packages/react-shadcn-ui/src/lib/src/components/form.tsx new file mode 100644 index 0000000000..44b9fcc275 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/form.tsx @@ -0,0 +1,572 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +/** + * Methods available on + */ +interface FlutterShadcnFormMethods { + /** + * Validate the form without saving. + * + * @returns true if the form is valid, false otherwise + */ + validate(): boolean; + /** + * Save and validate the form. Dispatches 'submit' event if valid. + * + * @returns true if the form is valid and submitted, false otherwise + */ + submit(): boolean; + /** + * Reset the form to its initial values. Dispatches 'reset' event. + */ + reset(): void; + /** + * Get the value of a specific form field. + * + * @param fieldId - The id of the field + * @returns The field's current value + */ + getFieldValue(fieldId: string): any; + /** + * Set the value of a specific form field. + * + * @param fieldId - The id of the field + * @param value - The value to set + */ + setFieldValue(fieldId: string, value: any): void; + /** + * Set an error message for a specific form field. + * + * @param fieldId - The id of the field + * @param error - The error message, or null to clear the error + */ + setFieldError(fieldId: string, error: string | null): void; +} +export interface FlutterShadcnFormProps { + /** + * Disable all form fields. + */ + disabled?: boolean; + /** + * Auto-validation mode for the form. + * + * Options: + * - 'disabled': No auto validation + * - 'always': Always validate + * - 'onUserInteraction': Validate after user interaction + * - 'alwaysAfterFirstValidation': Validate always after first validation (default) + */ + autoValidateMode?: 'disabled' | 'always' | 'onUserInteraction' | 'alwaysAfterFirstValidation'; + /** + * Current form values as a JSON string. + * + * Get: Returns all form field values as a JSON string. + * Set: Accepts a JSON string or object to set form values. + */ + value?: string; + /** + * Fired when form is successfully submitted (after validation passes). + * The event detail contains the form values. + */ + onSubmit?: (event: CustomEvent) => void; + /** + * Fired when form is reset. + */ + onReset?: (event: Event) => void; + /** + * Fired when any form field value changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +/** + * Element interface with methods/properties accessible via ref + * @example + * ```tsx + * const ref = useRef(null); + * // Call methods on the element + * ref.current?.finishRefresh('success'); + * // Access properties + * console.log(ref.current?.disabled); + * ``` + */ +export interface FlutterShadcnFormElement extends WebFElementWithMethods<{ + /** + * Validate the form without saving. + * + * @returns true if the form is valid, false otherwise + */ + validate(): boolean; + /** + * Save and validate the form. Dispatches 'submit' event if valid. + * + * @returns true if the form is valid and submitted, false otherwise + */ + submit(): boolean; + /** + * Reset the form to its initial values. Dispatches 'reset' event. + */ + reset(): void; + /** + * Get the value of a specific form field. + * + * @param fieldId - The id of the field + * @returns The field's current value + */ + getFieldValue(fieldId: string): any; + /** + * Set the value of a specific form field. + * + * @param fieldId - The id of the field + * @param value - The value to set + */ + setFieldValue(fieldId: string, value: any): void; + /** + * Set an error message for a specific form field. + * + * @param fieldId - The id of the field + * @param error - The error message, or null to clear the error + */ + setFieldError(fieldId: string, error: string | null): void; +}> { + /** Disable all form fields. */ + disabled?: boolean; + /** Auto-validation mode for the form. */ + autoValidateMode?: 'disabled' | 'always' | 'onUserInteraction' | 'alwaysAfterFirstValidation'; + /** Current form values as a JSON string. */ + value?: string; +} +/** + * Properties for +A form container that manages form state and validation using shadcn_ui's ShadForm. +@example +```html + + + + Submit + +``` +@example +```javascript +const form = document.getElementById('myForm'); +// Submit form and get values +if (form.submit()) { + const values = JSON.parse(form.value); + console.log('Form values:', values); +} +// Set form values +form.value = JSON.stringify({ username: 'john', email: 'john@example.com' }); +// Get/set individual field values +form.setFieldValue('username', 'jane'); +console.log(form.getFieldValue('username')); +// Set field errors +form.setFieldError('email', 'Invalid email format'); +// Reset form +form.reset(); +``` + * + * @example + * ```tsx + * const ref = useRef(null); + * + * + * Content + * + * + * // Call methods on the element + * ref.current?.finishRefresh('success'); + * ``` + */ +export const FlutterShadcnForm = createWebFComponent({ + tagName: 'flutter-shadcn-form', + displayName: 'FlutterShadcnForm', + // Map props to attributes + attributeProps: [ + 'disabled', + 'autoValidateMode', + 'value', + ], + // Convert prop names to attribute names if needed + attributeMap: { + autoValidateMode: 'auto-validate-mode', + }, + // Event handlers + events: [ + { + propName: 'onSubmit', + eventName: 'submit', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + { + propName: 'onReset', + eventName: 'reset', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnFormFieldProps { + /** + * Unique identifier for the field within the form. + * Used to access field values via form.getFieldValue(fieldId). + */ + fieldId?: string; + /** + * Label text displayed above the field. + */ + label?: string; + /** + * Description text shown below the field. + */ + description?: string; + /** + * Error message to display. Overrides validation errors. + */ + error?: string; + /** + * Whether this field is required. + * Adds a "*" indicator and validates that the field is not empty. + */ + required?: boolean; + /** + * Input type (used when no children are provided). + * Default: 'text' + */ + type?: string; + /** + * Placeholder text for the input field. + */ + placeholder?: string; + /** + * Initial value for the field. + */ + initialValue?: string; + /** + * Fired when the field value changes. + * The event detail contains the new value. + */ + onChange?: (event: CustomEvent) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnFormFieldElement extends WebFElementWithMethods<{ +}> { + /** Unique identifier for the field within the form. */ + fieldId?: string; + /** Label text displayed above the field. */ + label?: string; + /** Description text shown below the field. */ + description?: string; + /** Error message to display. Overrides validation errors. */ + error?: string; + /** Whether this field is required. */ + required?: boolean; + /** Input type (used when no children are provided). */ + type?: string; + /** Placeholder text for the input field. */ + placeholder?: string; + /** Initial value for the field. */ + initialValue?: string; +} +/** + * Properties for +A form field that automatically integrates with the parent form. +When used without children, renders a ShadInputFormField. +When used with children, wraps them with label, description, and error display. +@example +```html + + + + + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnFormField = createWebFComponent({ + tagName: 'flutter-shadcn-form-field', + displayName: 'FlutterShadcnFormField', + // Map props to attributes + attributeProps: [ + 'fieldId', + 'label', + 'description', + 'error', + 'required', + 'type', + 'placeholder', + 'initialValue', + ], + // Convert prop names to attribute names if needed + attributeMap: { + fieldId: 'field-id', + initialValue: 'initial-value', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnFormLabelProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnFormLabelElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Label element for form fields. +Typically used inside a custom form field layout. +@example +```html +Username +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnFormLabel = createWebFComponent({ + tagName: 'flutter-shadcn-form-label', + displayName: 'FlutterShadcnFormLabel', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnFormDescriptionProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnFormDescriptionElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Description text for form fields. +Provides additional context or instructions. +@example +```html + + This is your public display name. + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnFormDescription = createWebFComponent({ + tagName: 'flutter-shadcn-form-description', + displayName: 'FlutterShadcnFormDescription', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnFormMessageProps { + /** + * Type of message which determines the styling. + * + * Options: + * - 'error': Red text for validation errors (default) + * - 'success': Green text for success messages + * - 'info': Primary color for informational messages + */ + type?: 'error' | 'success' | 'info'; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnFormMessageElement extends WebFElementWithMethods<{ +}> { + /** Type of message which determines the styling. */ + type?: 'error' | 'success' | 'info'; +} +/** + * Properties for +Validation or status message for form fields. +@example +```html + + This field is required + + + Email is available + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnFormMessage = createWebFComponent({ + tagName: 'flutter-shadcn-form-message', + displayName: 'FlutterShadcnFormMessage', + // Map props to attributes + attributeProps: [ + 'type', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/icon_button.tsx b/packages/react-shadcn-ui/src/lib/src/components/icon_button.tsx new file mode 100644 index 0000000000..124e14a312 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/icon_button.tsx @@ -0,0 +1,154 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnIconButtonProps { + /** + * Visual variant of the icon button. + * - 'primary': Primary filled button (default) + * - 'secondary': Secondary muted button + * - 'destructive': Red destructive action button + * - 'outline': Bordered outline button + * - 'ghost': Transparent with hover effect + * + * Note: Unlike regular buttons, icon buttons do not support the 'link' variant. + * + * Default: 'primary' + */ + variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost'; + /** + * Name of the Lucide icon to display. + * + * Common icons include: + * - Navigation: 'chevron-right', 'chevron-left', 'arrow-right', 'arrow-left' + * - Actions: 'plus', 'minus', 'x', 'check', 'search', 'edit', 'trash', 'copy', 'share' + * - Objects: 'rocket', 'heart', 'star', 'home', 'user', 'mail', 'calendar', 'file' + * - UI: 'menu', 'ellipsis', 'more-vertical', 'grid', 'list', 'filter' + * - Status: 'info', 'alert-circle', 'help', 'check-circle', 'x-circle' + * - Formatting: 'bold', 'italic', 'underline', 'align-left', 'align-center', 'align-right' + * + * @example "rocket" + * @example "plus" + * @example "chevron-right" + */ + icon?: string; + /** + * Size of the icon in pixels. + * + * Default: 16 + */ + iconSize?: number; + /** + * Disable button interactions. + * + * When disabled, the button will not respond to clicks and will have a muted appearance. + */ + disabled?: boolean; + /** + * Show loading spinner and disable interactions. + * + * When loading, the icon is replaced with a circular progress indicator. + */ + loading?: boolean; + /** + * Fired when the button is pressed. + * Not emitted when disabled or loading. + */ + onClick?: (event: Event) => void; + /** + * Fired when the button is long-pressed. + * Not emitted when disabled or loading. + */ + onLongpress?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnIconButtonElement extends WebFElementWithMethods<{ +}> { + /** Visual variant of the icon button. */ + variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost'; + /** Name of the Lucide icon to display. */ + icon?: string; + /** Size of the icon in pixels. */ + iconSize?: number; + /** Disable button interactions. */ + disabled?: boolean; + /** Show loading spinner and disable interactions. */ + loading?: boolean; +} +/** + * Properties for +An icon-only button component with multiple variants. +Unlike the regular button, this is specifically designed for icon-only use cases. +@example +```html + +``` +@example With gradient and shadow (via CSS) +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnIconButton = createWebFComponent({ + tagName: 'flutter-shadcn-icon-button', + displayName: 'FlutterShadcnIconButton', + // Map props to attributes + attributeProps: [ + 'variant', + 'icon', + 'iconSize', + 'disabled', + 'loading', + ], + // Convert prop names to attribute names if needed + attributeMap: { + iconSize: 'icon-size', + }, + // Event handlers + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onLongpress', + eventName: 'longpress', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/image.tsx b/packages/react-shadcn-ui/src/lib/src/components/image.tsx new file mode 100644 index 0000000000..b16e7082bd --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/image.tsx @@ -0,0 +1,123 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnImageProps { + /** + * Image source URL. + */ + src?: string; + /** + * Alt text for accessibility. + */ + alt?: string; + /** + * Image width in pixels. + */ + width?: string; + /** + * Image height in pixels. + */ + height?: string; + /** + * How to fit the image. + * Options: 'contain', 'cover', 'fill', 'none', 'scaleDown' + * Default: 'cover' + */ + fit?: string; + /** + * Fired when image loads successfully. + */ + onLoad?: (event: Event) => void; + /** + * Fired when image fails to load. + */ + onError?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnImageElement extends WebFElementWithMethods<{ +}> { + /** Image source URL. */ + src?: string; + /** Alt text for accessibility. */ + alt?: string; + /** Image width in pixels. */ + width?: string; + /** Image height in pixels. */ + height?: string; + /** How to fit the image. */ + fit?: string; +} +/** + * Properties for +An image component with loading and error states. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnImage = createWebFComponent({ + tagName: 'flutter-shadcn-image', + displayName: 'FlutterShadcnImage', + // Map props to attributes + attributeProps: [ + 'src', + 'alt', + 'width', + 'height', + 'fit', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onLoad', + eventName: 'load', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onError', + eventName: 'error', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/input.tsx b/packages/react-shadcn-ui/src/lib/src/components/input.tsx new file mode 100644 index 0000000000..5be84070d2 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/input.tsx @@ -0,0 +1,268 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnInputProps { + /** + * Current value of the input. + */ + value?: string; + /** + * Placeholder text shown when empty. + */ + placeholder?: string; + /** + * Input type. + * Options: 'text', 'password', 'email', 'number', 'tel', 'url', 'search' + * Default: 'text' + */ + type?: string; + /** + * Disable the input. + */ + disabled?: boolean; + /** + * Make the input read-only. + */ + readonly?: boolean; + /** + * Maximum length of the input value. + */ + maxlength?: string; + /** + * Minimum length of the input value. + */ + minlength?: string; + /** + * Pattern for validation (regex). + */ + pattern?: string; + /** + * Whether the input is required. + */ + required?: boolean; + /** + * Autofocus on mount. + */ + autofocus?: boolean; + /** + * Text alignment within the input. + * Options: 'start', 'end', 'left', 'right', 'center' + * Default: 'start' + */ + textalign?: string; + /** + * Controls automatic text capitalization behavior. + * Options: 'none', 'sentences', 'words', 'characters' + * Default: 'none' + */ + autocapitalize?: string; + /** + * Whether to enable autocorrect. + * Default: true + */ + autocorrect?: boolean; + /** + * Whether to show input suggestions. + * Default: true + */ + enablesuggestions?: boolean; + /** + * Hint for the keyboard action button. + * Options: 'done', 'go', 'next', 'search', 'send', 'previous', 'newline' + */ + enterkeyhint?: string; + /** + * Maximum number of lines for the input. Use for multi-line input. + */ + maxlines?: string; + /** + * Minimum number of lines for the input. + */ + minlines?: string; + /** + * Color of the cursor (e.g., '#FF0000', 'red'). + */ + cursorcolor?: string; + /** + * Color of the text selection highlight (e.g., '#0000FF', 'blue'). + */ + selectioncolor?: string; + /** + * Character used to obscure text in password mode. + * Default: '•' + */ + obscuringcharacter?: string; + /** + * Fired on every input change. + */ + onInput?: (event: Event) => void; + /** + * Fired when input loses focus. + */ + onChange?: (event: Event) => void; + /** + * Fired when input gains focus. + */ + onFocus?: (event: Event) => void; + /** + * Fired when input loses focus. + */ + onBlur?: (event: Event) => void; + /** + * Fired when the user submits the input (e.g., presses Enter/Done). + */ + onSubmit?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnInputElement extends WebFElementWithMethods<{ +}> { + /** Current value of the input. */ + value?: string; + /** Placeholder text shown when empty. */ + placeholder?: string; + /** Input type. */ + type?: string; + /** Disable the input. */ + disabled?: boolean; + /** Make the input read-only. */ + readonly?: boolean; + /** Maximum length of the input value. */ + maxlength?: string; + /** Minimum length of the input value. */ + minlength?: string; + /** Pattern for validation (regex). */ + pattern?: string; + /** Whether the input is required. */ + required?: boolean; + /** Autofocus on mount. */ + autofocus?: boolean; + /** Text alignment within the input. */ + textalign?: string; + /** Controls automatic text capitalization behavior. */ + autocapitalize?: string; + /** Whether to enable autocorrect. */ + autocorrect?: boolean; + /** Whether to show input suggestions. */ + enablesuggestions?: boolean; + /** Hint for the keyboard action button. */ + enterkeyhint?: string; + /** Maximum number of lines for the input. Use for multi-line input. */ + maxlines?: string; + /** Minimum number of lines for the input. */ + minlines?: string; + /** Color of the cursor (e.g., '#FF0000', 'red'). */ + cursorcolor?: string; + /** Color of the text selection highlight (e.g., '#0000FF', 'blue'). */ + selectioncolor?: string; + /** Character used to obscure text in password mode. */ + obscuringcharacter?: string; +} +/** + * Properties for +A styled text input field. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnInput = createWebFComponent({ + tagName: 'flutter-shadcn-input', + displayName: 'FlutterShadcnInput', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'type', + 'disabled', + 'readonly', + 'maxlength', + 'minlength', + 'pattern', + 'required', + 'autofocus', + 'textalign', + 'autocapitalize', + 'autocorrect', + 'enablesuggestions', + 'enterkeyhint', + 'maxlines', + 'minlines', + 'cursorcolor', + 'selectioncolor', + 'obscuringcharacter', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onInput', + eventName: 'input', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onFocus', + eventName: 'focus', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onBlur', + eventName: 'blur', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onSubmit', + eventName: 'submit', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/input_otp.tsx b/packages/react-shadcn-ui/src/lib/src/components/input_otp.tsx new file mode 100644 index 0000000000..d11647bdaf --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/input_otp.tsx @@ -0,0 +1,270 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnInputOtpProps { + /** + * Maximum number of characters (required). + */ + maxlength: string; + /** + * Current OTP value. + */ + value?: string; + /** + * Disable the input. + */ + disabled?: boolean; + /** + * Fired when the OTP value changes. + */ + onChange?: (event: Event) => void; + /** + * Fired when all slots are filled. + */ + onComplete?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnInputOtpElement extends WebFElementWithMethods<{ +}> { + /** Maximum number of characters (required). */ + maxlength: string; + /** Current OTP value. */ + value?: string; + /** Disable the input. */ + disabled?: boolean; +} +/** + * Properties for +Accessible one-time password input with individual character slots. +@example +```html + + + + + + + + + + + + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnInputOtp = createWebFComponent({ + tagName: 'flutter-shadcn-input-otp', + displayName: 'FlutterShadcnInputOtp', + // Map props to attributes + attributeProps: [ + 'maxlength', + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onComplete', + eventName: 'complete', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnInputOtpGroupProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnInputOtpGroupElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Groups OTP slots together visually. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnInputOtpGroup = createWebFComponent({ + tagName: 'flutter-shadcn-input-otp-group', + displayName: 'FlutterShadcnInputOtpGroup', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnInputOtpSlotProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnInputOtpSlotElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Individual character slot managed by the parent input. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnInputOtpSlot = createWebFComponent({ + tagName: 'flutter-shadcn-input-otp-slot', + displayName: 'FlutterShadcnInputOtpSlot', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnInputOtpSeparatorProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnInputOtpSeparatorElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Visual separator between OTP groups. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnInputOtpSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-input-otp-separator', + displayName: 'FlutterShadcnInputOtpSeparator', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/menubar.tsx b/packages/react-shadcn-ui/src/lib/src/components/menubar.tsx new file mode 100644 index 0000000000..60ea1fea23 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/menubar.tsx @@ -0,0 +1,570 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +interface FlutterShadcnMenubarRadioGroupChangeEventDetail { + value: string | null; +} +export interface FlutterShadcnMenubarProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarElement extends WebFElementWithMethods<{ +}> { +} +/** + * A horizontal menubar that contains a list of menus. + * @example + * ```tsx + * + * + * File + * + * New Tab + * + * + * + * ``` + */ +export const FlutterShadcnMenubar = createWebFComponent({ + tagName: 'flutter-shadcn-menubar', + displayName: 'FlutterShadcnMenubar', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarMenuProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarMenuElement extends WebFElementWithMethods<{ +}> { +} +/** + * A single menu in the menubar, containing a trigger and content. + */ +export const FlutterShadcnMenubarMenu = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-menu', + displayName: 'FlutterShadcnMenubarMenu', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * The trigger label for a menubar menu. + */ +export const FlutterShadcnMenubarTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-trigger', + displayName: 'FlutterShadcnMenubarTrigger', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Container for the dropdown menu items within a menubar menu. + */ +export const FlutterShadcnMenubarContent = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-content', + displayName: 'FlutterShadcnMenubarContent', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * Keyboard shortcut to display (e.g., "⌘T", "Ctrl+N"). + */ + shortcut?: string; + /** + * Whether to use inset styling (adds left padding for alignment with checkbox/radio items). + */ + inset?: boolean; + /** + * Fired when the item is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** Keyboard shortcut to display. */ + shortcut?: string; + /** Whether to use inset styling. */ + inset?: boolean; +} +/** + * A menu item within a menubar menu. + */ +export const FlutterShadcnMenubarItem = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-item', + displayName: 'FlutterShadcnMenubarItem', + attributeProps: [ + 'disabled', + 'shortcut', + 'inset', + ], + attributeMap: {}, + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarSeparatorProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarSeparatorElement extends WebFElementWithMethods<{ +}> { +} +/** + * A separator line within a menubar menu. + */ +export const FlutterShadcnMenubarSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-separator', + displayName: 'FlutterShadcnMenubarSeparator', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarLabelProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarLabelElement extends WebFElementWithMethods<{ +}> { +} +/** + * A label/header for grouping menubar items. + */ +export const FlutterShadcnMenubarLabel = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-label', + displayName: 'FlutterShadcnMenubarLabel', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarSubProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarSubElement extends WebFElementWithMethods<{ +}> { +} +/** + * A container for nested submenu items within a menubar menu. + */ +export const FlutterShadcnMenubarSub = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-sub', + displayName: 'FlutterShadcnMenubarSub', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarSubTriggerProps { + /** + * Whether the submenu trigger is disabled. + */ + disabled?: boolean; + /** + * Whether to use inset styling. + */ + inset?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarSubTriggerElement extends WebFElementWithMethods<{ +}> { + /** Whether the submenu trigger is disabled. */ + disabled?: boolean; + /** Whether to use inset styling. */ + inset?: boolean; +} +/** + * The trigger element for a menubar submenu. + */ +export const FlutterShadcnMenubarSubTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-sub-trigger', + displayName: 'FlutterShadcnMenubarSubTrigger', + attributeProps: [ + 'disabled', + 'inset', + ], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarSubContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarSubContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Container for submenu items within a menubar. + */ +export const FlutterShadcnMenubarSubContent = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-sub-content', + displayName: 'FlutterShadcnMenubarSubContent', + attributeProps: [], + attributeMap: {}, + events: [], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarCheckboxItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * Whether the checkbox is checked. + */ + checked?: boolean; + /** + * Keyboard shortcut to display (e.g., "⌘B"). + */ + shortcut?: string; + /** + * Fired when the checked state changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarCheckboxItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** Whether the checkbox is checked. */ + checked?: boolean; + /** Keyboard shortcut to display. */ + shortcut?: string; +} +/** + * A menu item with a checkbox indicator in a menubar menu. + */ +export const FlutterShadcnMenubarCheckboxItem = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-checkbox-item', + displayName: 'FlutterShadcnMenubarCheckboxItem', + attributeProps: [ + 'disabled', + 'checked', + 'shortcut', + ], + attributeMap: {}, + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarRadioGroupProps { + /** + * The value of the currently selected radio item. + */ + value?: string; + /** + * Fired when the selected value changes. + */ + onChange?: (event: CustomEvent) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarRadioGroupElement extends WebFElementWithMethods<{ +}> { + /** The value of the currently selected radio item. */ + value?: string; +} +/** + * A group of radio items where only one can be selected. + */ +export const FlutterShadcnMenubarRadioGroup = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-radio-group', + displayName: 'FlutterShadcnMenubarRadioGroup', + attributeProps: [ + 'value', + ], + attributeMap: {}, + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent) => void) => (event: Event) => { + callback(event as CustomEvent); + }, + }, + ], + defaultProps: {}, +}); +export interface FlutterShadcnMenubarRadioItemProps { + /** + * Whether the item is disabled. + */ + disabled?: boolean; + /** + * The value of this radio item. + */ + value?: string; + /** + * Keyboard shortcut to display. + */ + shortcut?: string; + /** + * Fired when the item is clicked. + */ + onClick?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnMenubarRadioItemElement extends WebFElementWithMethods<{ +}> { + /** Whether the item is disabled. */ + disabled?: boolean; + /** The value of this radio item. */ + value?: string; + /** Keyboard shortcut to display. */ + shortcut?: string; +} +/** + * A radio-style menu item within a menubar radio group. + */ +export const FlutterShadcnMenubarRadioItem = createWebFComponent({ + tagName: 'flutter-shadcn-menubar-radio-item', + displayName: 'FlutterShadcnMenubarRadioItem', + attributeProps: [ + 'disabled', + 'value', + 'shortcut', + ], + attributeMap: {}, + events: [ + { + propName: 'onClick', + eventName: 'click', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + defaultProps: {}, +}); diff --git a/packages/react-shadcn-ui/src/lib/src/components/popover.tsx b/packages/react-shadcn-ui/src/lib/src/components/popover.tsx new file mode 100644 index 0000000000..733efda2de --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/popover.tsx @@ -0,0 +1,217 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnPopoverProps { + /** + * Whether the popover is open. + */ + open?: boolean; + /** + * Placement of the popover. + * Options: 'top', 'bottom', 'left', 'right' + * Default: 'bottom' + */ + placement?: string; + /** + * Close when clicking outside. + * Default: true + */ + closeOnOutsideClick?: boolean; + /** + * Fired when popover opens. + */ + onOpen?: (event: Event) => void; + /** + * Fired when popover closes. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnPopoverElement extends WebFElementWithMethods<{ +}> { + /** Whether the popover is open. */ + open?: boolean; + /** Placement of the popover. */ + placement?: string; + /** Close when clicking outside. */ + closeOnOutsideClick?: boolean; +} +/** + * Properties for +A floating content container that appears on trigger. +@example +```html + + + Open + + + Popover content here. + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnPopover = createWebFComponent({ + tagName: 'flutter-shadcn-popover', + displayName: 'FlutterShadcnPopover', + // Map props to attributes + attributeProps: [ + 'open', + 'placement', + 'closeOnOutsideClick', + ], + // Convert prop names to attribute names if needed + attributeMap: { + closeOnOutsideClick: 'close-on-outside-click', + }, + // Event handlers + events: [ + { + propName: 'onOpen', + eventName: 'open', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnPopoverTriggerProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnPopoverTriggerElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Trigger element for the popover. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnPopoverTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-popover-trigger', + displayName: 'FlutterShadcnPopoverTrigger', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnPopoverContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnPopoverContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Content of the popover. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnPopoverContent = createWebFComponent({ + tagName: 'flutter-shadcn-popover-content', + displayName: 'FlutterShadcnPopoverContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/progress.tsx b/packages/react-shadcn-ui/src/lib/src/components/progress.tsx new file mode 100644 index 0000000000..8182d4ca2f --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/progress.tsx @@ -0,0 +1,119 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnProgressProps { + /** + * Current progress value. + */ + value?: string; + /** + * Maximum value. + * Default: 100 + */ + max?: string; + /** + * Visual variant. + * Options: 'default', 'indeterminate' + * Default: 'default' + */ + variant?: string; + /** + * Background color of the progress track. + * Accepts hex color string (e.g. '#e0e0e0', '#FF808080'). + */ + backgroundColor?: string; + /** + * Color of the progress indicator. + * Accepts hex color string (e.g. '#3b82f6', '#FF0000FF'). + */ + color?: string; + /** + * Minimum height of the progress bar in logical pixels. + * Default: 16 + */ + minHeight?: string; + /** + * Border radius of the progress bar in logical pixels. + * Applied uniformly to all corners. + * Default: 16 + */ + borderRadius?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnProgressElement extends WebFElementWithMethods<{ +}> { + /** Current progress value. */ + value?: string; + /** Maximum value. */ + max?: string; + /** Visual variant. */ + variant?: string; + /** Background color of the progress track. */ + backgroundColor?: string; + /** Color of the progress indicator. */ + color?: string; + /** Minimum height of the progress bar in logical pixels. */ + minHeight?: string; + /** Border radius of the progress bar in logical pixels. */ + borderRadius?: string; +} +/** + * Properties for +A progress indicator component. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnProgress = createWebFComponent({ + tagName: 'flutter-shadcn-progress', + displayName: 'FlutterShadcnProgress', + // Map props to attributes + attributeProps: [ + 'value', + 'max', + 'variant', + 'backgroundColor', + 'color', + 'minHeight', + 'borderRadius', + ], + // Convert prop names to attribute names if needed + attributeMap: { + backgroundColor: 'background-color', + minHeight: 'min-height', + borderRadius: 'border-radius', + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/radio_group.tsx b/packages/react-shadcn-ui/src/lib/src/components/radio_group.tsx new file mode 100644 index 0000000000..4f7c72b9ec --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/radio_group.tsx @@ -0,0 +1,162 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnRadioGroupProps { + /** + * Currently selected value. + */ + value?: string; + /** + * Disable all radio items. + */ + disabled?: boolean; + /** + * Orientation of the radio group. + * Options: 'horizontal', 'vertical' + * Default: 'vertical' + */ + orientation?: string; + /** + * Fired when selection changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnRadioGroupElement extends WebFElementWithMethods<{ +}> { + /** Currently selected value. */ + value?: string; + /** Disable all radio items. */ + disabled?: boolean; + /** Orientation of the radio group. */ + orientation?: string; +} +/** + * Properties for + * Container for radio button groups. + * @example + * ```html + * + * Option 1 + * Option 2 + * + * ``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnRadioGroup = createWebFComponent({ + tagName: 'flutter-shadcn-radio-group', + displayName: 'FlutterShadcnRadioGroup', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + 'orientation', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnRadioGroupItemProps { + /** + * Value of this radio option. + */ + value: string; + /** + * Disable this specific radio item. + */ + disabled?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnRadioGroupItemElement extends WebFElementWithMethods<{ +}> { + /** Value of this radio option. */ + value: string; + /** Disable this specific radio item. */ + disabled?: boolean; +} +/** + * Properties for + * Individual radio button option. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnRadioGroupItem = createWebFComponent({ + tagName: 'flutter-shadcn-radio-group-item', + displayName: 'FlutterShadcnRadioGroupItem', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); diff --git a/packages/react-shadcn-ui/src/lib/src/components/scroll_area.tsx b/packages/react-shadcn-ui/src/lib/src/components/scroll_area.tsx new file mode 100644 index 0000000000..4d5ea6310f --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/scroll_area.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnScrollAreaProps { + /** + * Orientation of the scroll area. + * Options: 'vertical', 'horizontal', 'both' + * Default: 'vertical' + */ + orientation?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnScrollAreaElement extends WebFElementWithMethods<{ +}> { + /** Orientation of the scroll area. */ + orientation?: string; +} +/** + * Properties for +A scrollable area with styled scrollbars. +@example +```html + +
Scrollable content...
+
+``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnScrollArea = createWebFComponent({ + tagName: 'flutter-shadcn-scroll-area', + displayName: 'FlutterShadcnScrollArea', + // Map props to attributes + attributeProps: [ + 'orientation', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/select.tsx b/packages/react-shadcn-ui/src/lib/src/components/select.tsx new file mode 100644 index 0000000000..3d7533cd05 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/select.tsx @@ -0,0 +1,540 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSelectProps { + /** + * Currently selected value. + */ + value?: string; + /** + * Placeholder text when no value is selected. + */ + placeholder?: string; + /** + * Disable the select. + */ + disabled?: boolean; + /** + * Allow multiple selection. + */ + multiple?: boolean; + /** + * Allow searching/filtering options. + */ + searchable?: boolean; + /** + * Placeholder for search input when searchable. + */ + searchPlaceholder?: string; + /** + * Allow deselecting the current selection. + */ + allowDeselection?: boolean; + /** + * Whether to close the popover after selecting an option. + * Default: true for single select, configurable for multiple. + */ + closeOnSelect?: boolean; + /** + * Fired when selection changes. + * Event detail contains { value: string }. + */ + onChange?: (event: CustomEvent<{ value: string }>) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectElement extends WebFElementWithMethods<{ +}> { + /** Currently selected value. */ + value?: string; + /** Placeholder text when no value is selected. */ + placeholder?: string; + /** Disable the select. */ + disabled?: boolean; + /** Allow multiple selection. */ + multiple?: boolean; + /** Allow searching/filtering options. */ + searchable?: boolean; + /** Placeholder for search input when searchable. */ + searchPlaceholder?: string; + /** Allow deselecting the current selection. */ + allowDeselection?: boolean; + /** Whether to close the popover after selecting an option. */ + closeOnSelect?: boolean; +} +/** + * Properties for +A dropdown select component with support for single/multiple selection and search. +@example +```html + + + Apple + Banana + Orange + + + + + + Apple + Banana + + + + + + Eastern Standard Time + Central Standard Time + + + Greenwich Mean Time + Central European Time + + + + + React + Vue + Angular + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelect = createWebFComponent({ + tagName: 'flutter-shadcn-select', + displayName: 'FlutterShadcnSelect', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'disabled', + 'multiple', + 'searchable', + 'searchPlaceholder', + 'allowDeselection', + 'closeOnSelect', + ], + // Convert prop names to attribute names if needed + attributeMap: { + searchPlaceholder: 'search-placeholder', + allowDeselection: 'allow-deselection', + closeOnSelect: 'close-on-select', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: CustomEvent<{ value: string }>) => void) => (event: Event) => { + callback(event as CustomEvent<{ value: string }>); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectTriggerProps { + /** + * Placeholder text when no value is selected. + */ + placeholder?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectTriggerElement extends WebFElementWithMethods<{ +}> { + /** Placeholder text when no value is selected. */ + placeholder?: string; +} +/** + * Properties for +The trigger element that displays the selected value and opens the dropdown. +@example +```html + + + + ... + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-select-trigger', + displayName: 'FlutterShadcnSelectTrigger', + // Map props to attributes + attributeProps: [ + 'placeholder', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Container for the dropdown content/options. +@example +```html + + Option 1 + Option 2 + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectContent = createWebFComponent({ + tagName: 'flutter-shadcn-select-content', + displayName: 'FlutterShadcnSelectContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectItemProps { + /** + * Value of this option. + */ + value: string; + /** + * Disable this specific option. + */ + disabled?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectItemElement extends WebFElementWithMethods<{ +}> { + /** Value of this option. */ + value: string; + /** Disable this specific option. */ + disabled?: boolean; +} +/** + * Properties for +Individual select option. +@example +```html +Apple +Banana (out of stock) +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectItem = createWebFComponent({ + tagName: 'flutter-shadcn-select-item', + displayName: 'FlutterShadcnSelectItem', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectGroupProps { + /** + * Label for this option group. + */ + label?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectGroupElement extends WebFElementWithMethods<{ +}> { + /** Label for this option group. */ + label?: string; +} +/** + * Properties for +Group of select options with optional label. +@example +```html + + Apple + Banana + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectGroup = createWebFComponent({ + tagName: 'flutter-shadcn-select-group', + displayName: 'FlutterShadcnSelectGroup', + // Map props to attributes + attributeProps: [ + 'label', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectLabelProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectLabelElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +A label/header for a section of options (not inside a group). +@example +```html +Fruits +Apple +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectLabel = createWebFComponent({ + tagName: 'flutter-shadcn-select-label', + displayName: 'FlutterShadcnSelectLabel', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSelectSeparatorProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSelectSeparatorElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Visual separator between options. +@example +```html +Option 1 + +Option 2 +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSelectSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-select-separator', + displayName: 'FlutterShadcnSelectSeparator', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/separator.tsx b/packages/react-shadcn-ui/src/lib/src/components/separator.tsx new file mode 100644 index 0000000000..aa1e1b10d1 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/separator.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSeparatorProps { + /** + * Orientation of the separator. + * Options: 'horizontal', 'vertical' + * Default: 'horizontal' + */ + orientation?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSeparatorElement extends WebFElementWithMethods<{ +}> { + /** Orientation of the separator. */ + orientation?: string; +} +/** + * Properties for +A visual separator/divider component. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSeparator = createWebFComponent({ + tagName: 'flutter-shadcn-separator', + displayName: 'FlutterShadcnSeparator', + // Map props to attributes + attributeProps: [ + 'orientation', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/sheet.tsx b/packages/react-shadcn-ui/src/lib/src/components/sheet.tsx new file mode 100644 index 0000000000..b9142e8bac --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/sheet.tsx @@ -0,0 +1,373 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSheetProps { + /** + * Whether the sheet is open. + */ + open?: boolean; + /** + * Side from which the sheet appears. + * Options: 'top', 'bottom', 'left', 'right' + * Default: 'right' + */ + side?: string; + /** + * Close when clicking outside. + * Default: true + */ + closeOnOutsideClick?: boolean; + /** + * Fired when sheet opens. + */ + onOpen?: (event: Event) => void; + /** + * Fired when sheet closes. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetElement extends WebFElementWithMethods<{ +}> { + /** Whether the sheet is open. */ + open?: boolean; + /** Side from which the sheet appears. */ + side?: string; + /** Close when clicking outside. */ + closeOnOutsideClick?: boolean; +} +/** + * Properties for +A slide-out panel component. +@example +```html + + + Settings + + + Sheet content here. + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheet = createWebFComponent({ + tagName: 'flutter-shadcn-sheet', + displayName: 'FlutterShadcnSheet', + // Map props to attributes + attributeProps: [ + 'open', + 'side', + 'closeOnOutsideClick', + ], + // Convert prop names to attribute names if needed + attributeMap: { + closeOnOutsideClick: 'close-on-outside-click', + }, + // Event handlers + events: [ + { + propName: 'onOpen', + eventName: 'open', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSheetHeaderProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetHeaderElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Header slot for sheet. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheetHeader = createWebFComponent({ + tagName: 'flutter-shadcn-sheet-header', + displayName: 'FlutterShadcnSheetHeader', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSheetTitleProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetTitleElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Title within sheet header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheetTitle = createWebFComponent({ + tagName: 'flutter-shadcn-sheet-title', + displayName: 'FlutterShadcnSheetTitle', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSheetDescriptionProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetDescriptionElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Description within sheet header. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheetDescription = createWebFComponent({ + tagName: 'flutter-shadcn-sheet-description', + displayName: 'FlutterShadcnSheetDescription', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSheetContentProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetContentElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Main content slot for sheet. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheetContent = createWebFComponent({ + tagName: 'flutter-shadcn-sheet-content', + displayName: 'FlutterShadcnSheetContent', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnSheetFooterProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSheetFooterElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Footer slot for sheet. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSheetFooter = createWebFComponent({ + tagName: 'flutter-shadcn-sheet-footer', + displayName: 'FlutterShadcnSheetFooter', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/skeleton.tsx b/packages/react-shadcn-ui/src/lib/src/components/skeleton.tsx new file mode 100644 index 0000000000..e4bc0cdef2 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/skeleton.tsx @@ -0,0 +1,81 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSkeletonProps { + /** + * Width of the skeleton in pixels. + */ + width?: string; + /** + * Height of the skeleton in pixels. + */ + height?: string; + /** + * Whether the skeleton is circular. + */ + circle?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSkeletonElement extends WebFElementWithMethods<{ +}> { + /** Width of the skeleton in pixels. */ + width?: string; + /** Height of the skeleton in pixels. */ + height?: string; + /** Whether the skeleton is circular. */ + circle?: boolean; +} +/** + * Properties for +A skeleton loading placeholder. +@example +```html + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSkeleton = createWebFComponent({ + tagName: 'flutter-shadcn-skeleton', + displayName: 'FlutterShadcnSkeleton', + // Map props to attributes + attributeProps: [ + 'width', + 'height', + 'circle', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/slider.tsx b/packages/react-shadcn-ui/src/lib/src/components/slider.tsx new file mode 100644 index 0000000000..84a8d0f422 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/slider.tsx @@ -0,0 +1,134 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSliderProps { + /** + * Current value of the slider. + */ + value?: string; + /** + * Minimum value. + * Default: 0 + */ + min?: string; + /** + * Maximum value. + * Default: 100 + */ + max?: string; + /** + * Step increment. + * Default: 1 + */ + step?: string; + /** + * Disable the slider. + */ + disabled?: boolean; + /** + * Orientation of the slider. + * Options: 'horizontal', 'vertical' + * Default: 'horizontal' + */ + orientation?: string; + /** + * Fired continuously while sliding. + */ + onInput?: (event: Event) => void; + /** + * Fired when sliding ends. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSliderElement extends WebFElementWithMethods<{ +}> { + /** Current value of the slider. */ + value?: string; + /** Minimum value. */ + min?: string; + /** Maximum value. */ + max?: string; + /** Step increment. */ + step?: string; + /** Disable the slider. */ + disabled?: boolean; + /** Orientation of the slider. */ + orientation?: string; +} +/** + * Properties for +A slider control for selecting a value from a range. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSlider = createWebFComponent({ + tagName: 'flutter-shadcn-slider', + displayName: 'FlutterShadcnSlider', + // Map props to attributes + attributeProps: [ + 'value', + 'min', + 'max', + 'step', + 'disabled', + 'orientation', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onInput', + eventName: 'input', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/switch.tsx b/packages/react-shadcn-ui/src/lib/src/components/switch.tsx new file mode 100644 index 0000000000..21684c7685 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/switch.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnSwitchProps { + /** + * Whether the switch is on. + */ + checked?: boolean; + /** + * Disable the switch. + */ + disabled?: boolean; + /** + * Fired when the switch state changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnSwitchElement extends WebFElementWithMethods<{ +}> { + /** Whether the switch is on. */ + checked?: boolean; + /** Disable the switch. */ + disabled?: boolean; +} +/** + * Properties for +A toggle switch control. +@example +```html + + Enable notifications + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnSwitch = createWebFComponent({ + tagName: 'flutter-shadcn-switch', + displayName: 'FlutterShadcnSwitch', + // Map props to attributes + attributeProps: [ + 'checked', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/table.tsx b/packages/react-shadcn-ui/src/lib/src/components/table.tsx new file mode 100644 index 0000000000..d6d388a962 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/table.tsx @@ -0,0 +1,327 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnTableProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +A data table component. +@example +```html + + + + Name + Status + + + + + John + Active + + + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTable = createWebFComponent({ + tagName: 'flutter-shadcn-table', + displayName: 'FlutterShadcnTable', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTableHeaderProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableHeaderElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnTableHeader - WebF FlutterShadcnTableHeader component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTableHeader = createWebFComponent({ + tagName: 'flutter-shadcn-table-header', + displayName: 'FlutterShadcnTableHeader', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTableBodyProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableBodyElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnTableBody - WebF FlutterShadcnTableBody component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTableBody = createWebFComponent({ + tagName: 'flutter-shadcn-table-body', + displayName: 'FlutterShadcnTableBody', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTableRowProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableRowElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnTableRow - WebF FlutterShadcnTableRow component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTableRow = createWebFComponent({ + tagName: 'flutter-shadcn-table-row', + displayName: 'FlutterShadcnTableRow', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTableHeadProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableHeadElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnTableHead - WebF FlutterShadcnTableHead component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTableHead = createWebFComponent({ + tagName: 'flutter-shadcn-table-head', + displayName: 'FlutterShadcnTableHead', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTableCellProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTableCellElement extends WebFElementWithMethods<{ +}> { +} +/** + * FlutterShadcnTableCell - WebF FlutterShadcnTableCell component + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTableCell = createWebFComponent({ + tagName: 'flutter-shadcn-table-cell', + displayName: 'FlutterShadcnTableCell', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/tabs.tsx b/packages/react-shadcn-ui/src/lib/src/components/tabs.tsx new file mode 100644 index 0000000000..9c8c870b57 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/tabs.tsx @@ -0,0 +1,269 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnTabsProps { + /** + * Currently active tab value. + */ + value?: string; + /** + * Default tab value (uncontrolled mode). + */ + defaultValue?: string; + /** + * Fired when active tab changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTabsElement extends WebFElementWithMethods<{ +}> { + /** Currently active tab value. */ + value?: string; + /** Default tab value (uncontrolled mode). */ + defaultValue?: string; +} +/** + * Properties for +A tabbed interface component. +@example +```html + + + Account + Password + + Account content here. + Password content here. + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTabs = createWebFComponent({ + tagName: 'flutter-shadcn-tabs', + displayName: 'FlutterShadcnTabs', + // Map props to attributes + attributeProps: [ + 'value', + 'defaultValue', + ], + // Convert prop names to attribute names if needed + attributeMap: { + defaultValue: 'default-value', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTabsListProps { + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTabsListElement extends WebFElementWithMethods<{ +}> { +} +/** + * Properties for +Container for tab triggers. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTabsList = createWebFComponent({ + tagName: 'flutter-shadcn-tabs-list', + displayName: 'FlutterShadcnTabsList', + // Map props to attributes + attributeProps: [ + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTabsTriggerProps { + /** + * Value identifier for this tab. + */ + value: string; + /** + * Disable this tab. + */ + disabled?: boolean; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTabsTriggerElement extends WebFElementWithMethods<{ +}> { + /** Value identifier for this tab. */ + value: string; + /** Disable this tab. */ + disabled?: boolean; +} +/** + * Properties for +Individual tab trigger button. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTabsTrigger = createWebFComponent({ + tagName: 'flutter-shadcn-tabs-trigger', + displayName: 'FlutterShadcnTabsTrigger', + // Map props to attributes + attributeProps: [ + 'value', + 'disabled', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); +export interface FlutterShadcnTabsContentProps { + /** + * Value identifier matching a trigger. + */ + value: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTabsContentElement extends WebFElementWithMethods<{ +}> { + /** Value identifier matching a trigger. */ + value: string; +} +/** + * Properties for +Content panel for a tab. + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTabsContent = createWebFComponent({ + tagName: 'flutter-shadcn-tabs-content', + displayName: 'FlutterShadcnTabsContent', + // Map props to attributes + attributeProps: [ + 'value', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/textarea.tsx b/packages/react-shadcn-ui/src/lib/src/components/textarea.tsx new file mode 100644 index 0000000000..f9e3014a65 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/textarea.tsx @@ -0,0 +1,163 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnTextareaProps { + /** + * Current value of the textarea. + */ + value?: string; + /** + * Placeholder text shown when empty. + */ + placeholder?: string; + /** + * Number of visible text rows. + * Default: 3 + */ + rows?: string; + /** + * Disable the textarea. + */ + disabled?: boolean; + /** + * Make the textarea read-only. + */ + readonly?: boolean; + /** + * Maximum length of the input value. + */ + maxlength?: string; + /** + * Whether the textarea is required. + */ + required?: boolean; + /** + * Autofocus on mount. + */ + autofocus?: boolean; + /** + * Fired on every input change. + */ + onInput?: (event: Event) => void; + /** + * Fired when textarea loses focus. + */ + onChange?: (event: Event) => void; + /** + * Fired when textarea gains focus. + */ + onFocus?: (event: Event) => void; + /** + * Fired when textarea loses focus. + */ + onBlur?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTextareaElement extends WebFElementWithMethods<{ +}> { + /** Current value of the textarea. */ + value?: string; + /** Placeholder text shown when empty. */ + placeholder?: string; + /** Number of visible text rows. */ + rows?: string; + /** Disable the textarea. */ + disabled?: boolean; + /** Make the textarea read-only. */ + readonly?: boolean; + /** Maximum length of the input value. */ + maxlength?: string; + /** Whether the textarea is required. */ + required?: boolean; + /** Autofocus on mount. */ + autofocus?: boolean; +} +/** + * Properties for +A multi-line text input field. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTextarea = createWebFComponent({ + tagName: 'flutter-shadcn-textarea', + displayName: 'FlutterShadcnTextarea', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'rows', + 'disabled', + 'readonly', + 'maxlength', + 'required', + 'autofocus', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onInput', + eventName: 'input', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onFocus', + eventName: 'focus', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + { + propName: 'onBlur', + eventName: 'blur', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/time_picker.tsx b/packages/react-shadcn-ui/src/lib/src/components/time_picker.tsx new file mode 100644 index 0000000000..a1087bbe12 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/time_picker.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnTimePickerProps { + /** + * Selected time in HH:mm format. + */ + value?: string; + /** + * Placeholder text when no time is selected. + */ + placeholder?: string; + /** + * Disable the picker. + */ + disabled?: boolean; + /** + * Use 24-hour format. + * Default: true + */ + use24Hour?: boolean; + /** + * Fired when time selection changes. + */ + onChange?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTimePickerElement extends WebFElementWithMethods<{ +}> { + /** Selected time in HH:mm format. */ + value?: string; + /** Placeholder text when no time is selected. */ + placeholder?: string; + /** Disable the picker. */ + disabled?: boolean; + /** Use 24-hour format. */ + use24Hour?: boolean; +} +/** + * Properties for +A time picker component. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTimePicker = createWebFComponent({ + tagName: 'flutter-shadcn-time-picker', + displayName: 'FlutterShadcnTimePicker', + // Map props to attributes + attributeProps: [ + 'value', + 'placeholder', + 'disabled', + 'use24Hour', + ], + // Convert prop names to attribute names if needed + attributeMap: { + use24Hour: 'use-24-hour', + }, + // Event handlers + events: [ + { + propName: 'onChange', + eventName: 'change', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/toast.tsx b/packages/react-shadcn-ui/src/lib/src/components/toast.tsx new file mode 100644 index 0000000000..2dd6c75bd8 --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/toast.tsx @@ -0,0 +1,110 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnToastProps { + /** + * Visual variant of the toast. + * - 'default': Standard toast + * - 'destructive': Red error toast + * Default: 'default' + */ + variant?: string; + /** + * Title of the toast. + */ + title?: string; + /** + * Description text. + */ + description?: string; + /** + * Duration in milliseconds before auto-dismiss. + * Set to 0 to disable auto-dismiss. + * Default: 5000 + */ + duration?: string; + /** + * Show close button. + */ + closable?: boolean; + /** + * Fired when toast is dismissed. + */ + onClose?: (event: Event) => void; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnToastElement extends WebFElementWithMethods<{ +}> { + /** Visual variant of the toast. */ + variant?: string; + /** Title of the toast. */ + title?: string; + /** Description text. */ + description?: string; + /** Duration in milliseconds before auto-dismiss. */ + duration?: string; + /** Show close button. */ + closable?: boolean; +} +/** + * Properties for +A toast notification component. +@example +```html + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnToast = createWebFComponent({ + tagName: 'flutter-shadcn-toast', + displayName: 'FlutterShadcnToast', + // Map props to attributes + attributeProps: [ + 'variant', + 'title', + 'description', + 'duration', + 'closable', + ], + // Convert prop names to attribute names if needed + attributeMap: { + }, + // Event handlers + events: [ + { + propName: 'onClose', + eventName: 'close', + handler: (callback: (event: Event) => void) => (event: Event) => { + callback(event as Event); + }, + }, + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/components/tooltip.tsx b/packages/react-shadcn-ui/src/lib/src/components/tooltip.tsx new file mode 100644 index 0000000000..7761c0bada --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/components/tooltip.tsx @@ -0,0 +1,95 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnTooltipProps { + /** + * Text content of the tooltip. + */ + content?: string; + /** + * Delay before showing tooltip in milliseconds. + * Default: 200 + */ + showDelay?: string; + /** + * Delay before hiding tooltip in milliseconds. + * Default: 0 + */ + hideDelay?: string; + /** + * Placement of the tooltip relative to the trigger. + * Options: 'top', 'bottom', 'left', 'right' + * Default: 'top' + */ + placement?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnTooltipElement extends WebFElementWithMethods<{ +}> { + /** Text content of the tooltip. */ + content?: string; + /** Delay before showing tooltip in milliseconds. */ + showDelay?: string; + /** Delay before hiding tooltip in milliseconds. */ + hideDelay?: string; + /** Placement of the tooltip relative to the trigger. */ + placement?: string; +} +/** + * Properties for +A tooltip component that shows additional information on hover. +@example +```html + + Hover me + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTooltip = createWebFComponent({ + tagName: 'flutter-shadcn-tooltip', + displayName: 'FlutterShadcnTooltip', + // Map props to attributes + attributeProps: [ + 'content', + 'showDelay', + 'hideDelay', + 'placement', + ], + // Convert prop names to attribute names if needed + attributeMap: { + showDelay: 'show-delay', + hideDelay: 'hide-delay', + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/lib/src/theme/theme.tsx b/packages/react-shadcn-ui/src/lib/src/theme/theme.tsx new file mode 100644 index 0000000000..2ad6b8fe0d --- /dev/null +++ b/packages/react-shadcn-ui/src/lib/src/theme/theme.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { createWebFComponent, WebFElementWithMethods } from "@openwebf/react-core-ui"; +import * as __webfTypes from "../../../types"; +export interface FlutterShadcnThemeProps { + /** + * The color scheme to use for theming. + * Available options: 'blue', 'gray', 'green', 'neutral', 'orange', + * 'red', 'rose', 'slate', 'stone', 'violet', 'yellow', 'zinc'. + * Default: 'zinc' + */ + colorScheme?: string; + /** + * The brightness mode for the theme. + * - 'light': Light mode + * - 'dark': Dark mode + * - 'system': Follow system preference + * Default: 'system' + */ + brightness?: string; + /** + * Radius multiplier for border radius values. + * Default: 0.5 + */ + radius?: string; + /** + * HTML id attribute + */ + id?: string; + /** + * Additional CSS styles + */ + style?: React.CSSProperties; + /** + * Children elements + */ + children?: React.ReactNode; + /** + * Additional CSS class names + */ + className?: string; +} +export interface FlutterShadcnThemeElement extends WebFElementWithMethods<{ +}> { + /** The color scheme to use for theming. */ + colorScheme?: string; + /** The brightness mode for the theme. */ + brightness?: string; + /** Radius multiplier for border radius values. */ + radius?: string; +} +/** + * Properties for +Theme provider element that wraps content with shadcn_ui theming. +Use this as a root element to provide consistent theming to all +shadcn components within. +@example +```html + + Click me + +``` + * + * @example + * ```tsx + * + * + * Content + * + * ``` + */ +export const FlutterShadcnTheme = createWebFComponent({ + tagName: 'flutter-shadcn-theme', + displayName: 'FlutterShadcnTheme', + // Map props to attributes + attributeProps: [ + 'colorScheme', + 'brightness', + 'radius', + ], + // Convert prop names to attribute names if needed + attributeMap: { + colorScheme: 'color-scheme', + }, + // Event handlers + events: [ + ], + // Default prop values + defaultProps: { + // Add default values here + }, +}); \ No newline at end of file diff --git a/packages/react-shadcn-ui/src/types.ts b/packages/react-shadcn-ui/src/types.ts new file mode 100644 index 0000000000..6e4b18b902 --- /dev/null +++ b/packages/react-shadcn-ui/src/types.ts @@ -0,0 +1,2 @@ +/* Generated by WebF CLI - aggregated type declarations */ +export type ShadcnColorScheme = "blue" | "gray" | "green" | "neutral" | "orange" | "red" | "rose" | "slate" | "stone" | "violet" | "yellow" | "zinc"; \ No newline at end of file diff --git a/packages/react-shadcn-ui/tsconfig.json b/packages/react-shadcn-ui/tsconfig.json new file mode 100644 index 0000000000..92fa5851ee --- /dev/null +++ b/packages/react-shadcn-ui/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "jsx": "react-jsx", + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "baseUrl": ".", + "paths": { + "react": ["./node_modules/@types/react/index.d.ts"], + "react-dom": ["./node_modules/@types/react-dom/index.d.ts"], + "react/jsx-runtime": ["./node_modules/@types/react/jsx-runtime.d.ts"], + "react/jsx-dev-runtime": ["./node_modules/@types/react/jsx-dev-runtime.d.ts"] + } + }, + "include": ["src"] +} diff --git a/packages/react-shadcn-ui/tsdown.config.ts b/packages/react-shadcn-ui/tsdown.config.ts new file mode 100644 index 0000000000..7a76bc134b --- /dev/null +++ b/packages/react-shadcn-ui/tsdown.config.ts @@ -0,0 +1,8 @@ +module.exports = { + entry: ['src/index.ts'], + format: ['esm', 'cjs'], + dts: true, + sourcemap: true, + clean: true, + external: ['react', 'react-dom', '@openwebf/react-core-ui'], +}; diff --git a/use_cases/package.json b/use_cases/package.json index 12f07e05c5..9c95c4e0ea 100644 --- a/use_cases/package.json +++ b/use_cases/package.json @@ -8,7 +8,7 @@ "@openwebf/react-cupertino-ui": "^0.3.35", "@openwebf/react-lucide-icons": "^0.1.0", "@openwebf/react-router": "1.0.1", - "@openwebf/react-shadcn-ui": "^0.1.0", + "@openwebf/react-shadcn-ui": "link:../packages/react-shadcn-ui", "@openwebf/react-ui-kit": "^0.1.0-beta.1", "@openwebf/react-video-player": "^1.0.0", "@openwebf/webf-bluetooth": "^1.0.0", @@ -33,6 +33,7 @@ "scripts": { "start": "vite", "dev": "vite", + "prebuild": "pnpm -C ../packages/react-shadcn-ui install && pnpm -C ../packages/react-shadcn-ui run build", "build": "vite build", "preview": "vite preview", "test": "react-scripts test" diff --git a/use_cases/pnpm-lock.yaml b/use_cases/pnpm-lock.yaml index 13e8919035..a5549f309a 100644 --- a/use_cases/pnpm-lock.yaml +++ b/use_cases/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: 1.0.1 version: 1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@openwebf/react-shadcn-ui': - specifier: ^0.1.0 - version: 0.1.0(@openwebf/react-core-ui@0.24.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: link:../packages/react-shadcn-ui + version: link:../packages/react-shadcn-ui '@openwebf/react-ui-kit': specifier: ^0.1.0-beta.1 version: 0.1.0-beta.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -1253,13 +1253,6 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@openwebf/react-shadcn-ui@0.1.0': - resolution: {integrity: sha512-tYiuRknaK9IoLe9W1c8jI+XzJCauZuVle9HJIzsBmzqQUghY3cXruq3bTZGS72GNbHefjK10tbOHE9Yj2fSKQg==} - peerDependencies: - '@openwebf/react-core-ui': ^0.24.1 - react: '>=16.8.0' - react-dom: '>=16.8.0' - '@openwebf/react-ui-kit@0.1.0-beta.1': resolution: {integrity: sha512-Z95UhcaI304WI6nojZjk7o15ZVD0rGX9EpLbOoryOzdyY0R5yyl7oP1cmirilL8twvwXdKHqpiKm7XFYGQUtLw==} peerDependencies: @@ -1388,56 +1381,67 @@ packages: resolution: {integrity: sha512-9tS4QyfU5NF5CdUugEi7kWbcGD7pbu6Fm8SunuePH6beeQgtcRZ9K9KVwKHEgfBHeeyrr5OvfV1qWs7PMDOf5w==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.53.0': resolution: {integrity: sha512-U+0ovxGU9bVJIHfW+oALpHd0ho1YDwhj0yHASDzIj+bOeo+VzEpNtHxcjhFab0YcHUorIMoqyxckC98+81oTJw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.53.0': resolution: {integrity: sha512-Cp/TQ+wLjRTqTuiVwLz4XPZMo3ROl7EJYMF8HhMp8Uf+9kOOATB3/p4gGZPpuQ4BP7qEXG29ET24u9+F0ERYkQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.53.0': resolution: {integrity: sha512-SuGoAwhsSonrSTEZTiQOGC3+XZfq7rc/qAdAOBrYYIp8pu+Wh4EFFXl6+QYYNbNrHL3DnVoWACLwnfwlTa0neA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.53.0': resolution: {integrity: sha512-EOKej1x0WoePnJWfg7ZbnUqiuiQunshzsKZSIfTHFDiCY9pnsr3Weit1GjcpGnun7H5HuRREqkT2c9CcKxNwSg==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.53.0': resolution: {integrity: sha512-YAvv2aMFlfiawJ97lutomuehG2Yowd4YgsAqI85XNiMK9eBA1vEMZHt3BShg8cUvak71BM+VFRHddqc+OrRdVA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.53.0': resolution: {integrity: sha512-DxZe/sMVaqN+s5kVk3Iq619Rgyl1JCTob7xOLSNC84mbzg3NYTSheqqrtVllYjLYo4wm9YyqjVS57miuzNyXbQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.53.0': resolution: {integrity: sha512-N7+iZ0jEhwLY1FEsjbCR9lAxIZP0k+3Cghx9vSQWn+rcW8SgN8VcCmwJDoPDaGKTzWWB791U1s79BSLnEhUa0Q==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.53.0': resolution: {integrity: sha512-MA/NVneZyIskjvXdh2NR9YcPi7eHWBlQOWP2X8OymzyeUEB0JfUpmbKQZngHmOlyleV2IoR5nHIgMSRjLskOnA==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.53.0': resolution: {integrity: sha512-iYEYzYpfaSCkunVD0LOYrD9OMc357be7+rBuCxW1qvsjCGl+95iWnYAFfyEoxAm6koasNN3tFxFYze5MKl5S3A==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.53.0': resolution: {integrity: sha512-FoRekOqhRUKbJMsB5LvhQchDeFeNlS6UGUwi0p3860sxE4zE+lp07FnkuR+yQH0rSn6iLXsnr44jnorgl8mGlQ==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.53.0': resolution: {integrity: sha512-mEN2k1zKO5PUzW8W15hKpLh+zZI2by1onX2GfI93OekGbKN5aTjWGo7yAjwRZLjhAgs2UQcXmEWbIw0R5B4RnQ==} @@ -1561,24 +1565,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.0': resolution: {integrity: sha512-Q5ldc2bzriuzYEoAuqJ9Vr3FyZhakk5hiwDbniZ8tlEXpbjBhbOleGf9/gkhLaouDnkNUEazFW9mtqwUTRdh7Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.15.0': resolution: {integrity: sha512-pY4is+jEpOxlYCSnI+7N8Oxbap9TmTz5YT84tUvRTlOlTBwFAUlWFCX0FRwWJlsfP0TxbqhIe8dNNzlsEmJbXQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.0': resolution: {integrity: sha512-zYEt5eT8y8RUpoe7t5pjpoOdGu+/gSTExj8PV86efhj6ugB3bPlj3Y85ogdW3WMVXr4NvwqvzdaYGCZfXzSyVg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.0': resolution: {integrity: sha512-zC1rmOgFH5v2BCbByOazEqs0aRNpTdLRchDExfcCfgKgeaD+IdpUOqp7i3VG1YzkcnbuZjMlXfM0ugpt+CddoA==} @@ -7512,12 +7520,6 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@openwebf/react-shadcn-ui@0.1.0(@openwebf/react-core-ui@0.24.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@openwebf/react-core-ui': 0.24.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - '@openwebf/react-ui-kit@0.1.0-beta.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@openwebf/react-core-ui': 0.2.13(react-dom@19.2.0(react@19.2.0))(react@19.2.0) diff --git a/use_cases/src/App.tsx b/use_cases/src/App.tsx index a522ceb3da..5032a8a2e8 100644 --- a/use_cases/src/App.tsx +++ b/use_cases/src/App.tsx @@ -140,6 +140,8 @@ import { ShadcnContextMenuPage } from './pages/shadcn/ShadcnContextMenuPage'; import { ShadcnPopoverPage } from './pages/shadcn/ShadcnPopoverPage'; import { ShadcnFormPage } from './pages/shadcn/ShadcnFormPage'; import { ShadcnIconButtonPage } from './pages/shadcn/ShadcnIconButtonPage'; +import { ShadcnInputOtpPage } from './pages/shadcn/ShadcnInputOtpPage'; +import { ShadcnMenubarPage } from './pages/shadcn/ShadcnMenubarPage'; // Lucide Icons imports import { LucideShowcasePage } from './pages/LucideShowcasePage'; import { LucideIconsPage } from './pages/lucide/LucideIconsPage'; @@ -256,6 +258,8 @@ function App() { } /> } /> } /> + } /> + } /> )} diff --git a/use_cases/src/pages/BasicFormElementsPage.tsx b/use_cases/src/pages/BasicFormElementsPage.tsx index 003c02ad5a..9b0c2ae7d4 100644 --- a/use_cases/src/pages/BasicFormElementsPage.tsx +++ b/use_cases/src/pages/BasicFormElementsPage.tsx @@ -12,9 +12,22 @@ export const BasicFormElementsPage: React.FC = () => { setTextValue(e.target.value); }; + const selectRadioValue = (value: string) => { + console.log('selectRadioValue', value); + setRadioValue(value); + }; + const handleRadioChange = (e: React.ChangeEvent) => { console.log('handleRadioChange', e.target.value); - setRadioValue(e.target.value); + selectRadioValue(e.target.value); + }; + + const handleRadioInput = (e: React.FormEvent) => { + // WebF radio controls dispatch native "input" reliably; keep this as a fallback + // so selection still updates when React's radio onChange path is not triggered. + const value = e.currentTarget.value; + console.log('handleRadioInput', value); + selectRadioValue(value); }; const handleCheckboxChange = (e: React.ChangeEvent) => { @@ -35,7 +48,7 @@ export const BasicFormElementsPage: React.FC = () => { // Test functions to change states programmatically const testRadioChange = (value: string) => { console.log('Programmatically changing radio from', radioValue, 'to:', value); - setRadioValue(value); + selectRadioValue(value); }; const testCheckboxToggle = (value: string) => { @@ -79,42 +92,45 @@ export const BasicFormElementsPage: React.FC = () => {
Choose your favorite color:
-
Selected: "{radioValue}"
- + {/* Test buttons for radio */}

Test Radio Programmatically:

@@ -122,7 +138,7 @@ export const BasicFormElementsPage: React.FC = () => { Set Red
{ }}>Quick Start
- {quickStart.map((qs) => ( + {quickStart.filter((qs) => !qs.hidden).map((qs) => ( ))}
diff --git a/use_cases/src/pages/ShadcnShowcasePage.tsx b/use_cases/src/pages/ShadcnShowcasePage.tsx index fe50b64da9..63733dcf94 100644 --- a/use_cases/src/pages/ShadcnShowcasePage.tsx +++ b/use_cases/src/pages/ShadcnShowcasePage.tsx @@ -33,12 +33,13 @@ export const ShadcnShowcasePage: React.FC = () => {
- {/**/} + - {/**/} - {/**/} - {/**/} - {/**/} + + + + +

Display Components

@@ -46,13 +47,13 @@ export const ShadcnShowcasePage: React.FC = () => { - {/**/} - {/**/} + +

Navigation & Layout

- {/**/} + @@ -60,7 +61,7 @@ export const ShadcnShowcasePage: React.FC = () => {

Data & Pickers

- {/**/} +
@@ -68,7 +69,8 @@ export const ShadcnShowcasePage: React.FC = () => {
- {/**/} + +
diff --git a/use_cases/src/pages/shadcn/ShadcnInputOtpPage.tsx b/use_cases/src/pages/shadcn/ShadcnInputOtpPage.tsx new file mode 100644 index 0000000000..d22967393b --- /dev/null +++ b/use_cases/src/pages/shadcn/ShadcnInputOtpPage.tsx @@ -0,0 +1,105 @@ +import React, { useState } from 'react'; +import { WebFListView } from '@openwebf/react-core-ui'; +import { + FlutterShadcnTheme, + FlutterShadcnInputOtp, + FlutterShadcnInputOtpGroup, + FlutterShadcnInputOtpSlot, + FlutterShadcnInputOtpSeparator, +} from '@openwebf/react-shadcn-ui'; + +export const ShadcnInputOtpPage: React.FC = () => { + const [otpValue, setOtpValue] = useState(''); + const [completed, setCompleted] = useState(false); + + return ( + +
+ +

Input OTP

+ +
+

Basic OTP Input

+

Enter a 6-digit verification code.

+ { + setCompleted(false); + }} + onComplete={() => { + setCompleted(true); + }} + > + + + + + + + + + + + + + {completed && ( +

OTP complete!

+ )} +
+ +
+

4-Digit PIN

+

A shorter 4-digit code without separator.

+ + + + + + + + +
+ +
+

Disabled State

+

OTP input in disabled state.

+ + + + + + + + + + + + + +
+ +
+

Multiple Groups

+

6-character code split into groups of 2.

+ + + + + + + + + + + + + + + + +
+
+
+
+ ); +}; diff --git a/use_cases/src/pages/shadcn/ShadcnInputPage.tsx b/use_cases/src/pages/shadcn/ShadcnInputPage.tsx index 1ecfdcce76..18f804003a 100644 --- a/use_cases/src/pages/shadcn/ShadcnInputPage.tsx +++ b/use_cases/src/pages/shadcn/ShadcnInputPage.tsx @@ -10,6 +10,7 @@ import { export const ShadcnInputPage: React.FC = () => { const [inputValue, setInputValue] = useState(''); const [textareaValue, setTextareaValue] = useState(''); + const [submitted, setSubmitted] = useState(''); return ( @@ -42,6 +43,14 @@ export const ShadcnInputPage: React.FC = () => { placeholder="Enter password" />
+
+ + +
@@ -72,6 +81,100 @@ export const ShadcnInputPage: React.FC = () => { +
+

Text Alignment

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

Keyboard & Input Behavior

+
+
+ + +
+
+ + +
+
+ + +
+
+ + setSubmitted('Submitted!')} + /> + {submitted && ( + {submitted} + )} +
+
+
+ +
+

Multi-line Input

+
+
+ + +
+
+
+ +
+

Cursor & Selection Colors

+
+
+ + +
+
+ + +
+
+
+

Textarea

@@ -100,11 +203,16 @@ export const ShadcnInputPage: React.FC = () => {
- +
- +
diff --git a/use_cases/src/pages/shadcn/ShadcnMenubarPage.tsx b/use_cases/src/pages/shadcn/ShadcnMenubarPage.tsx new file mode 100644 index 0000000000..ba06b45342 --- /dev/null +++ b/use_cases/src/pages/shadcn/ShadcnMenubarPage.tsx @@ -0,0 +1,264 @@ +import React, { useState } from 'react'; +import { WebFListView } from '@openwebf/react-core-ui'; +import { + FlutterShadcnTheme, + FlutterShadcnMenubar, + FlutterShadcnMenubarMenu, + FlutterShadcnMenubarTrigger, + FlutterShadcnMenubarContent, + FlutterShadcnMenubarItem, + FlutterShadcnMenubarSeparator, + FlutterShadcnMenubarLabel, + FlutterShadcnMenubarSub, + FlutterShadcnMenubarSubTrigger, + FlutterShadcnMenubarSubContent, + FlutterShadcnMenubarCheckboxItem, + FlutterShadcnMenubarRadioGroup, + FlutterShadcnMenubarRadioItem, +} from '@openwebf/react-shadcn-ui'; + +export const ShadcnMenubarPage: React.FC = () => { + const [showBookmarksBar, setShowBookmarksBar] = useState(true); + const [showFullUrls, setShowFullUrls] = useState(false); + const [showStatusBar, setShowStatusBar] = useState(true); + const [selectedPerson, setSelectedPerson] = useState('benoit'); + + const handleAction = (action: string) => { + console.log(`Menubar action: ${action}`); + }; + + return ( + +
+ +

Menubar

+ +
+

Complete Menubar

+

+ A full-featured menubar with items, shortcuts, submenus, checkboxes, and radio groups. +

+ + {/* File Menu */} + + File + + handleAction('newTab')}> + New Tab + + handleAction('newWindow')}> + New Window + + + New Incognito Window + + + + Share + + handleAction('emailLink')}> + Email link + + handleAction('messages')}> + Messages + + handleAction('notes')}> + Notes + + + + + handleAction('print')}> + Print... + + + + + {/* Edit Menu */} + + Edit + + handleAction('undo')}> + Undo + + handleAction('redo')}> + Redo + + + + Find + + handleAction('searchWeb')}> + Search the web + + + handleAction('find')}> + Find... + + handleAction('findNext')}> + Find Next + + handleAction('findPrev')}> + Find Previous + + + + + handleAction('cut')}> + Cut + + handleAction('copy')}> + Copy + + handleAction('paste')}> + Paste + + + + + {/* View Menu */} + + View + + setShowBookmarksBar(!showBookmarksBar)} + > + Always Show Bookmarks Bar + + setShowFullUrls(!showFullUrls)} + > + Always Show Full URLs + + + handleAction('reload')}> + Reload + + + Force Reload + + + handleAction('toggleFullscreen')}> + Toggle Fullscreen + + + handleAction('hideSidebar')}> + Hide Sidebar + + + + + {/* Profiles Menu */} + + Profiles + + ) => { + if (e.detail?.value) { + setSelectedPerson(e.detail.value); + } + }} + > + + Andy + + + Benoit + + + Luis + + + + handleAction('editProfiles')}> + Edit... + + + handleAction('addProfile')}> + Add Profile... + + + + +
+ +
+

Simple Menubar

+

+ A minimal menubar with basic items and shortcuts. +

+ + + File + + handleAction('new')}> + New + + handleAction('open')}> + Open + + handleAction('save')}> + Save + + + handleAction('exit')}> + Exit + + + + + Help + + handleAction('about')}> + About + + + + +
+ +
+

Menubar with Status Bar Toggle

+

+ Demonstrates checkbox items to toggle visibility of UI elements. +

+ + + View + + setShowStatusBar(!showStatusBar)} + > + Status Bar + + setShowBookmarksBar(!showBookmarksBar)} + > + Bookmarks Bar + + setShowFullUrls(!showFullUrls)} + > + Full URLs + + + + + {showStatusBar && ( +
+

Status bar is visible

+
+ )} +
+
+
+
+ ); +}; diff --git a/use_cases/src/pages/shadcn/ShadcnPopoverPage.tsx b/use_cases/src/pages/shadcn/ShadcnPopoverPage.tsx index b7b7f6ba99..f6a27ec61b 100644 --- a/use_cases/src/pages/shadcn/ShadcnPopoverPage.tsx +++ b/use_cases/src/pages/shadcn/ShadcnPopoverPage.tsx @@ -115,6 +115,100 @@ export const ShadcnPopoverPage: React.FC = () => {
+
+

Popover Placement

+

+ Use the placement prop to control where the popover appears. +

+
+ + + Top + + +

Placed on top

+
+
+ + + Bottom + + +

Placed on bottom

+
+
+ + + Left + + +

Placed on left

+
+
+ + + Right + + +

Placed on right

+
+
+
+
+ +
+

Popover Alignment

+

+ Use the align prop to fine-tune positioning within the placement direction. +

+
+ + + Bottom Start + + +

Aligned to start

+
+
+ + + Bottom Center + + +

Aligned to center

+
+
+ + + Bottom End + + +

Aligned to end

+
+
+
+
+ +
+

Controlled Popover

+

+ Use closeOnOutsideClick={false} to prevent closing when clicking outside. +

+ + + Sticky Popover + + +
+

Sticky popover

+

+ This won't close when clicking outside. Click the trigger again to close. +

+
+
+
+
+

Popover with Actions

diff --git a/use_cases/src/pages/shadcn/ShadcnProgressPage.tsx b/use_cases/src/pages/shadcn/ShadcnProgressPage.tsx index fb901c402f..80261d64a1 100644 --- a/use_cases/src/pages/shadcn/ShadcnProgressPage.tsx +++ b/use_cases/src/pages/shadcn/ShadcnProgressPage.tsx @@ -109,6 +109,124 @@ export const ShadcnProgressPage: React.FC = () => {
+
+

Indeterminate

+
+
+

Default indeterminate animation

+ +
+
+

Indeterminate with custom color

+ +
+
+
+ +
+

Custom Colors

+
+
+

Blue indicator

+ +
+
+

Green indicator

+ +
+
+

Red indicator

+ +
+
+

Purple indicator with custom background

+ +
+
+

Orange indicator with dark background

+ +
+
+
+ +
+

Custom Height

+
+
+

Thin (4px)

+ +
+
+

Default (16px)

+ +
+
+

Thick (24px)

+ +
+
+

Extra thick (32px)

+ +
+
+
+ +
+

Custom Border Radius

+
+
+

Square corners (0)

+ +
+
+

Slightly rounded (4)

+ +
+
+

Default rounded (16)

+ +
+
+
+ +
+

Combined Customization

+
+
+

Download Progress

+

2.4 GB / 4.0 GB

+ +
+
+

Storage Used

+

85% of 100 GB

+ +
+
+

Battery Level

+

72% remaining

+ +
+
+
+

Multi-step Progress

diff --git a/use_cases/src/pages/shadcn/ShadcnRadioPage.tsx b/use_cases/src/pages/shadcn/ShadcnRadioPage.tsx index cd74b8c110..b158bb3e94 100644 --- a/use_cases/src/pages/shadcn/ShadcnRadioPage.tsx +++ b/use_cases/src/pages/shadcn/ShadcnRadioPage.tsx @@ -2,14 +2,43 @@ import React, { useState } from 'react'; import { WebFListView } from '@openwebf/react-core-ui'; import { FlutterShadcnTheme, - FlutterShadcnRadio, - FlutterShadcnRadioItem, + FlutterShadcnRadioGroup, + FlutterShadcnRadioGroupItem, } from '@openwebf/react-shadcn-ui'; +const resolveRadioValue = (event: any): string | null => { + const detail = event?.detail; + + if (typeof detail === 'string' && detail) { + return detail; + } + + if (detail && typeof detail === 'object' && typeof detail.value === 'string' && detail.value) { + return detail.value; + } + + const targetValue = event?.target?.value; + if (typeof targetValue === 'string' && targetValue) { + return targetValue; + } + + return null; +}; + export const ShadcnRadioPage: React.FC = () => { const [selectedPlan, setSelectedPlan] = useState('comfortable'); const [selectedSize, setSelectedSize] = useState('medium'); + const selectPlan = (value: string) => { + console.log('selectPlan', value); + setSelectedPlan(value); + }; + + const selectSize = (value: string) => { + console.log('selectSize', value); + setSelectedSize(value); + }; + return (
@@ -20,96 +49,58 @@ export const ShadcnRadioPage: React.FC = () => {

Basic Radio Group

- setSelectedPlan(e.detail?.value || 'comfortable')} + onChange={(event: any) => { + console.log('plan group change', event?.detail); + const nextValue = resolveRadioValue(event); + if (nextValue) { + selectPlan(nextValue); + } + }} > -
-
- - -
-
- - -
-
- - -
-
-
+ Default + Comfortable + Compact +

Selected: {selectedPlan}

Size Selection

- setSelectedSize(e.detail?.value || 'medium')} + onChange={(event: any) => { + console.log('size group change', event?.detail); + const nextValue = resolveRadioValue(event); + if (nextValue) { + selectSize(nextValue); + } + }} > -
-
- - -
-
- - -
-
- - -
-
-
+ Small + Medium + Large +

Selected size: {selectedSize}

With Descriptions

- -
-
- -
- -

Best for small teams just getting started.

-
-
-
- -
- -

For growing teams that need more features.

-
-
-
- -
- -

For large organizations with custom needs.

-
-
-
-
+ + Startup + Business + Enterprise +

Disabled State

- -
-
- - -
-
- - -
-
-
+ + Option 1 (disabled) + Option 2 (disabled) +