Skip to content

Commit

Permalink
feat: tab (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
nank1ro authored Jul 3, 2024
1 parent e3f997e commit 96505e3
Show file tree
Hide file tree
Showing 19 changed files with 1,528 additions and 24 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.6.0

- Add `ShadTabs` component
- Add `ShadColorScheme.fromName` to easily create a color scheme from a name (String)
- Add `package` to `ShadImage` (thanks to @farhanfadila1717)
- Fix `decoration` of form fields
- Fix selection controls of `ShadInput`

## 0.5.7

- Renamed the breakpoints
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
compile:
cd playground && flutter build web --web-renderer canvaskit
cd playground && flutter build web --web-renderer canvaskit --no-tree-shake-icons

deploy:
cd playground && firebase deploy
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ See the [documentation](https://mariuti.com/shadcn-ui/) to interact with the com
- [ ] Sonner (?)
- [x] [Switch](https://mariuti.com/shadcn-ui/components/switch/)
- [x] [Table](https://mariuti.com/shadcn-ui/components/table/)
- [ ] Tabs
- [x] [Tabs](https://mariuti.com/shadcn-ui/components/tabs/)
- [ ] TextArea
- [x] [Toast](https://mariuti.com/shadcn-ui/components/toast/)
- [ ] Toggle
Expand Down
18 changes: 11 additions & 7 deletions example/lib/common/base_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class BaseScaffold extends StatelessWidget {
this.crossAxisAlignment = CrossAxisAlignment.center,
this.wrapChildrenInScrollable = true,
this.wrapSingleChildInColumn = true,
this.alignment,
});

final List<Widget> children;
Expand All @@ -20,19 +21,22 @@ class BaseScaffold extends StatelessWidget {
final CrossAxisAlignment crossAxisAlignment;
final bool wrapChildrenInScrollable;
final bool wrapSingleChildInColumn;
final Alignment? alignment;

@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final size = MediaQuery.sizeOf(context);

Widget left = Center(
child: children.length == 1 && !wrapSingleChildInColumn
? children[0]
: Column(
crossAxisAlignment: crossAxisAlignment,
children: children.separatedBy(const SizedBox(height: 8)),
));
Widget left = Align(
alignment: alignment ?? Alignment.center,
child: children.length == 1 && !wrapSingleChildInColumn
? children[0]
: Column(
crossAxisAlignment: crossAxisAlignment,
children: children.separatedBy(const SizedBox(height: 8)),
),
);

if (wrapChildrenInScrollable) {
left = SingleChildScrollView(
Expand Down
4 changes: 3 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import 'package:example/pages/sheet.dart';
import 'package:example/pages/slider.dart';
import 'package:example/pages/switch.dart';
import 'package:example/pages/switch_form_field.dart';
import 'package:example/pages/tabs.dart';
import 'package:example/pages/table.dart';
import 'package:example/pages/toast.dart';
import 'package:example/pages/tooltip.dart';
Expand Down Expand Up @@ -53,17 +54,18 @@ final routes = <String, WidgetBuilder>{
'/progress': (_) => const ProgressPage(),
'/radio-group': (_) => const RadioPage(),
'/radio-group-form-field': (_) => const RadioGroupFormFieldPage(),
'/resizable': (_) => const ResizablePage(),
'/select': (_) => const SelectPage(),
'/select-form-field': (_) => const SelectFormFieldPage(),
'/sheet': (_) => const SheetPage(),
'/slider': (_) => const SliderPage(),
'/switch': (_) => const SwitchPage(),
'/switch-form-field': (_) => const SwitchFormFieldPage(),
'/tabs': (_) => const TabsPage(),
'/table': (_) => const TablePage(),
'/toast': (_) => const ToastPage(),
'/tooltip': (_) => const TooltipPage(),
'/typography': (_) => const TypographyPage(),
'/resizable': (_) => const ResizablePage(),
};
final routeToNameRegex = RegExp('(?:^/|-)([a-z])');

Expand Down
77 changes: 77 additions & 0 deletions example/lib/pages/tabs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:example/common/base_scaffold.dart';
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';

class TabsPage extends StatelessWidget {
const TabsPage({super.key});

@override
Widget build(BuildContext context) {
return BaseScaffold(
appBarTitle: "Tabs",
wrapChildrenInScrollable: false,
wrapSingleChildInColumn: false,
alignment: Alignment.topCenter,
children: [
ShadTabs<String>(
defaultValue: 'account',
tabBarConstraints: const BoxConstraints(maxWidth: 400),
contentConstraints: const BoxConstraints(maxWidth: 400),
tabs: [
ShadTab(
value: 'account',
text: const Text('Account'),
content: ShadCard(
title: const Text('Account'),
description: const Text(
"Make changes to your account here. Click save when you're done."),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 16),
ShadInputFormField(
label: const Text('Name'),
initialValue: 'Ale',
),
const SizedBox(height: 8),
ShadInputFormField(
label: const Text('Username'),
initialValue: 'nank1ro',
),
const SizedBox(height: 16),
],
),
footer: const ShadButton(text: Text('Save changes')),
),
),
ShadTab(
value: 'password',
text: const Text('Password'),
content: ShadCard(
title: const Text('Password'),
description: const Text(
"Change your password here. After saving, you'll be logged out."),
content: Column(
children: [
const SizedBox(height: 16),
ShadInputFormField(
label: const Text('Current password'),
obscureText: true,
),
const SizedBox(height: 8),
ShadInputFormField(
label: const Text('New password'),
obscureText: true,
),
const SizedBox(height: 16),
],
),
footer: const ShadButton(text: Text('Save password')),
),
),
],
),
],
);
}
}
4 changes: 3 additions & 1 deletion lib/shadcn_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ export 'src/components/input.dart';
export 'src/components/popover.dart';
export 'src/components/progress.dart';
export 'src/components/radio.dart';
export 'src/components/resizable.dart';
export 'src/components/select.dart';
export 'src/components/sheet.dart';
export 'src/components/slider.dart';
export 'src/components/switch.dart';
export 'src/components/tabs.dart';
export 'src/components/table.dart';
export 'src/components/toast.dart';
export 'src/components/tooltip.dart';
export 'src/components/resizable.dart';

// Raw Components
export 'src/raw_components/portal.dart';
Expand Down Expand Up @@ -81,6 +82,7 @@ export 'src/theme/components/tooltip.dart';
export 'src/theme/text_theme/text_styles_default.dart';
export 'src/theme/text_theme/theme.dart';
export 'src/theme/components/resizable.dart';
export 'src/theme/components/tabs.dart';

// Utils
export 'src/utils/position.dart';
Expand Down
12 changes: 9 additions & 3 deletions lib/src/components/form/field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@ class ShadFormBuilderField<T> extends FormField<T> {
hasError ? error ?? Text(field.errorText!) : null;

return ShadDecorator(
// The decoration is set to none because the component itself has
// its own decoration
decoration: ShadDecoration.none,
// borders are handled by the field itself
decoration: const ShadDecoration(
border: ShadBorder.none,
secondaryBorder: ShadBorder.none,
errorBorder: ShadBorder.none,
focusedBorder: ShadBorder.none,
secondaryErrorBorder: ShadBorder.none,
secondaryFocusedBorder: ShadBorder.none,
),
label: label,
hasError: hasError,
error: effectiveError,
Expand Down
17 changes: 12 additions & 5 deletions lib/src/components/image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
this.antialiasing = true,
this.semanticLabel,
this.svgTheme,
this.package,
}) : assert(
src is String || src is IconData,
'src must be a String or IconData',
Expand All @@ -53,6 +54,7 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
this.antialiasing = true,
this.semanticLabel,
this.svgTheme,
this.package,
}) : width = size,
height = size,
assert(
Expand Down Expand Up @@ -101,6 +103,9 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
/// The theme of the svg
final SvgTheme? svgTheme;

/// The package of the image, if any.
final String? package;

/// Returns `true` if the image is remote.
bool get isRemote => Uri.tryParse(src as String)?.host.isNotEmpty ?? false;

Expand Down Expand Up @@ -135,15 +140,15 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
//
// Finally, if there is a [gradient], apply a shader mask to the image.
if (isRemote) {
if (isSvg) {
image = SvgPicture.network(
sourceString,
if (isSvgVector) {
image = SvgPicture(
NetworkBytesLoader(Uri.parse(sourceString)),
width: width,
height: height,
fit: fit,
alignment: alignment,
colorFilter: colorFilter,
clipBehavior: Clip.antiAlias,
alignment: alignment,
placeholderBuilder:
placeholder != null ? (_) => placeholder! : null,
semanticsLabel: semanticLabel,
Expand Down Expand Up @@ -181,7 +186,7 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
}
} else if (isSvgVector) {
image = SvgPicture(
AssetBytesLoader(sourceString),
AssetBytesLoader(sourceString, packageName: package),
width: width,
height: height,
fit: fit,
Expand All @@ -202,6 +207,7 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
alignment: alignment,
placeholderBuilder: placeholder != null ? (_) => placeholder! : null,
semanticsLabel: semanticLabel,
package: package,
);
} else {
image = Image.asset(
Expand All @@ -219,6 +225,7 @@ class ShadImage<T extends ShadImageSrc> extends StatelessWidget {
return child;
},
semanticLabel: semanticLabel,
package: package,
);
}
}
Expand Down
17 changes: 16 additions & 1 deletion lib/src/components/input.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand Down Expand Up @@ -299,6 +300,19 @@ class ShadInputState extends State<ShadInput>
final effectiveMouseCursor =
widget.mouseCursor ?? WidgetStateMouseCursor.textable;

final defaultSelectionControls = switch (Theme.of(context).platform) {
TargetPlatform.iOS => cupertinoTextSelectionHandleControls,
TargetPlatform.macOS => cupertinoDesktopTextSelectionHandleControls,
TargetPlatform.android ||
TargetPlatform.fuchsia =>
materialTextSelectionHandleControls,
TargetPlatform.linux ||
TargetPlatform.windows =>
desktopTextSelectionHandleControls,
};
final effectiveSelectionControls =
widget.selectionControls ?? defaultSelectionControls;

return ShadDisabled(
disabled: !widget.enabled,
child: _selectionGestureDetectorBuilder.buildGestureDetector(
Expand Down Expand Up @@ -408,7 +422,7 @@ class ShadInputState extends State<ShadInput>
contextMenuBuilder:
widget.contextMenuBuilder,
selectionControls:
widget.selectionControls,
effectiveSelectionControls,
mouseCursor: effectiveMouseCursor,
enableInteractiveSelection:
widget.enableInteractiveSelection,
Expand All @@ -417,6 +431,7 @@ class ShadInputState extends State<ShadInput>
widget.spellCheckConfiguration,
textAlign: widget.textAlign,
onTapOutside: widget.onTapOutside,
rendererIgnoresPointer: true,
),
),
),
Expand Down
Loading

0 comments on commit 96505e3

Please sign in to comment.