@akira-io/ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/blocks.d.ts +186 -0
- package/dist/blocks.js +921 -0
- package/dist/blocks.js.map +1 -0
- package/dist/chunk-42BJBH56.js +786 -0
- package/dist/chunk-42BJBH56.js.map +1 -0
- package/dist/chunk-5MQWJVM2.js +1291 -0
- package/dist/chunk-5MQWJVM2.js.map +1 -0
- package/dist/chunk-A2SIZOEA.js +413 -0
- package/dist/chunk-A2SIZOEA.js.map +1 -0
- package/dist/chunk-POE7OYET.js +96 -0
- package/dist/chunk-POE7OYET.js.map +1 -0
- package/dist/chunk-UXL33CZ4.js +170 -0
- package/dist/chunk-UXL33CZ4.js.map +1 -0
- package/dist/date-range-filter-QEa8fhUM.d.ts +149 -0
- package/dist/index.d.ts +474 -0
- package/dist/index.js +3094 -0
- package/dist/index.js.map +1 -0
- package/dist/inertia.d.ts +41 -0
- package/dist/inertia.js +86 -0
- package/dist/inertia.js.map +1 -0
- package/dist/language-Bft6rBBt.d.ts +14 -0
- package/dist/locales/pt.d.ts +21 -0
- package/dist/locales/pt.js +79 -0
- package/dist/locales/pt.js.map +1 -0
- package/dist/shells.d.ts +121 -0
- package/dist/shells.js +101 -0
- package/dist/shells.js.map +1 -0
- package/dist/sidebar-BDhG9SUU.d.ts +88 -0
- package/dist/types-Cno1_Ijx.d.ts +40 -0
- package/dist/types-cOieac8G.d.ts +77 -0
- package/dist/types-u1qfmJQi.d.ts +28 -0
- package/package.json +142 -0
- package/theme.css +224 -0
- package/themes/nosferry.css +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NosFerry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner.svg" alt="Akira UI" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license: MIT">
|
|
7
|
+
<img src="https://img.shields.io/badge/react-18%20%7C%2019-61dafb.svg" alt="react 18 or 19">
|
|
8
|
+
<img src="https://img.shields.io/badge/package%20manager-bun-fbf0df.svg" alt="bun">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
Open-source React component library: the full shadcn/ui (New York) set on an OKLCH design-token system,
|
|
12
|
+
plus a handful of blocks and application shells built on top of it. The default palette is Akira purple.
|
|
13
|
+
Swap it for your own brand with a single CSS import, no component code changes required.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @akira-io/ui
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# npm
|
|
23
|
+
npm install @akira-io/ui
|
|
24
|
+
|
|
25
|
+
# pnpm
|
|
26
|
+
pnpm add @akira-io/ui
|
|
27
|
+
|
|
28
|
+
# yarn
|
|
29
|
+
yarn add @akira-io/ui
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Peer dependencies: `react` and `react-dom`, 18 or 19. `@inertiajs/react` is only needed if you import from
|
|
33
|
+
the `/inertia` entry point; `react-hook-form` is only needed for the `<Form>` component. Neither is required
|
|
34
|
+
for the primitives, the blocks, or the generic shells.
|
|
35
|
+
|
|
36
|
+
## Theme (Tailwind v4)
|
|
37
|
+
|
|
38
|
+
Import the tokens once, in your app's main CSS:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
@import 'tailwindcss';
|
|
42
|
+
@plugin 'tailwindcss-animate';
|
|
43
|
+
@import '@akira-io/ui/theme.css';
|
|
44
|
+
@source '../../node_modules/@akira-io/ui/dist';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`tailwindcss-animate` generates the `animate-in` / `fade-in` / `zoom-in` utility classes several components
|
|
48
|
+
use for enter and exit transitions (dialogs, dropdowns, tooltips). `@source` points Tailwind at the compiled
|
|
49
|
+
package output so those utility classes are not purged.
|
|
50
|
+
|
|
51
|
+
No configuration is required to get the default Akira purple palette: `theme.css` sets `--primary` from the
|
|
52
|
+
Akira ramp in both light and dark mode.
|
|
53
|
+
|
|
54
|
+
### Switching brands
|
|
55
|
+
|
|
56
|
+
Import a brand preset after `theme.css` and set `data-brand` on `<html>`:
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
@import '@akira-io/ui/theme.css';
|
|
60
|
+
@import '@akira-io/ui/themes/nosferry.css';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<html data-brand="nosferry"></html>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`themes/nosferry.css` ships today as the worked example: four custom properties (`--primary` and
|
|
68
|
+
`--primary-foreground`, light and dark) scoped to `[data-brand='nosferry']`. Write your own preset the same
|
|
69
|
+
way and ship it alongside your app; omitting `data-brand` renders Akira purple.
|
|
70
|
+
|
|
71
|
+
## Use components
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { Button, Card, cn } from '@akira-io/ui';
|
|
75
|
+
|
|
76
|
+
export function Example() {
|
|
77
|
+
return (
|
|
78
|
+
<Card>
|
|
79
|
+
<Button className={cn('gap-2')}>Continue</Button>
|
|
80
|
+
</Card>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The package is framework-agnostic at its core: the primitives and the tokens work in any React app (Inertia,
|
|
86
|
+
Next.js, plain Vite). Only the application shells need a router, and they take it as a prop rather than
|
|
87
|
+
importing one.
|
|
88
|
+
|
|
89
|
+
## Subpath exports
|
|
90
|
+
|
|
91
|
+
| Import | Contents |
|
|
92
|
+
| --------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `@akira-io/ui` | 55 shadcn/ui components + `cn` (zero framework coupling) |
|
|
94
|
+
| `@akira-io/ui/blocks` | 8 higher-level blocks: command palette, stat cards, settings cards, tour, and more |
|
|
95
|
+
| `@akira-io/ui/shells` | 12 application shell pieces: sidebar, header, nav, settings layout; take a polymorphic `linkComponent` prop |
|
|
96
|
+
| `@akira-io/ui/inertia` | The same shells with the Inertia `Link` and `usePage().url` pre-bound |
|
|
97
|
+
| `@akira-io/ui/theme.css` | The design tokens |
|
|
98
|
+
| `@akira-io/ui/themes/*.css` | Brand presets (`nosferry.css` ships as the example) |
|
|
99
|
+
| `@akira-io/ui/locales/pt` | Portuguese labels for the components that take them, as a typed object to spread |
|
|
100
|
+
|
|
101
|
+
Component text defaults to English. To render it in Portuguese, spread the locale object rather than
|
|
102
|
+
restating each prop:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { DataTable } from '@akira-io/ui';
|
|
106
|
+
import { dataTableLabelsPt } from '@akira-io/ui/locales/pt';
|
|
107
|
+
|
|
108
|
+
<DataTable {...dataTableLabelsPt} columns={columns} data={rows} />;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Documentation
|
|
112
|
+
|
|
113
|
+
Full documentation starts at [`docs/00-index.md`](docs/00-index.md):
|
|
114
|
+
|
|
115
|
+
- [Installation](docs/01-installation.md)
|
|
116
|
+
- [Theme & Tokens](docs/02-theme-and-tokens.md)
|
|
117
|
+
- [Components](docs/03-components.md)
|
|
118
|
+
- [Shells](docs/04-shells.md)
|
|
119
|
+
- [Adoption Guide](docs/05-adoption-guide.md)
|
|
120
|
+
- [Development & Release](docs/06-development.md)
|
|
121
|
+
|
|
122
|
+
A hosted documentation site is planned but does not exist yet.
|
|
123
|
+
|
|
124
|
+
## Testing
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
bun run test
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Changelog
|
|
131
|
+
|
|
132
|
+
Release notes are generated from conventional commits via [git-cliff](https://git-cliff.org) when a
|
|
133
|
+
`vX.Y.Z` tag is pushed (see `cliff.toml` and `.github/workflows/release.yml`). `CHANGELOG.md` appears in the
|
|
134
|
+
repository after the first tagged release.
|
|
135
|
+
|
|
136
|
+
## Contributing
|
|
137
|
+
|
|
138
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
139
|
+
|
|
140
|
+
## Security
|
|
141
|
+
|
|
142
|
+
Please review [SECURITY.md](SECURITY.md) for how to report a vulnerability.
|
|
143
|
+
|
|
144
|
+
## Credits
|
|
145
|
+
|
|
146
|
+
- [Kidiatoliny](https://github.com/kidiatoliny)
|
|
147
|
+
- [All Contributors](https://github.com/akira-io/ui/graphs/contributors)
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { D as DateFilterValue, a as DateFilterLabels, b as DateFilterOption, c as DateFilterUnit } from './types-cOieac8G.js';
|
|
2
|
+
export { C as CommandPalette, d as CommandPaletteGroup, e as CommandPaletteItem, f as CommandPaletteProps, g as DATE_FILTER_LABELS, h as DATE_FILTER_OPERATORS, i as DATE_FILTER_PRESETS, j as DATE_FILTER_UNITS, k as DateFilterMode, l as DateFilterOperator, u as useCommandPalette } from './types-cOieac8G.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ReactNode, PropsWithChildren, ReactElement } from 'react';
|
|
5
|
+
import { LucideIcon } from 'lucide-react';
|
|
6
|
+
import { S as SurfaceProps } from './language-Bft6rBBt.js';
|
|
7
|
+
import { T as TourStep, a as TourDefinition, b as TourBreakpoint, c as TourProgress, d as TourLabels } from './types-u1qfmJQi.js';
|
|
8
|
+
export { D as DEFAULT_TOUR_LABELS, e as TourOutcome } from './types-u1qfmJQi.js';
|
|
9
|
+
|
|
10
|
+
type DateFilterPanel = 'root' | 'fixed' | 'relative';
|
|
11
|
+
interface DateFilterContextValue {
|
|
12
|
+
value: DateFilterValue;
|
|
13
|
+
draft: DateFilterValue;
|
|
14
|
+
labels: DateFilterLabels;
|
|
15
|
+
presets: DateFilterOption[];
|
|
16
|
+
operators: DateFilterOption[];
|
|
17
|
+
units: DateFilterOption[];
|
|
18
|
+
panel: DateFilterPanel;
|
|
19
|
+
setDraft: (value: DateFilterValue) => void;
|
|
20
|
+
openPanel: (panel: DateFilterPanel, seed: DateFilterValue) => void;
|
|
21
|
+
backToRoot: () => void;
|
|
22
|
+
commit: (value: DateFilterValue) => void;
|
|
23
|
+
}
|
|
24
|
+
declare function useDateFilter(): DateFilterContextValue;
|
|
25
|
+
|
|
26
|
+
interface DateFilterProps {
|
|
27
|
+
value: DateFilterValue;
|
|
28
|
+
onChange: (value: DateFilterValue) => void;
|
|
29
|
+
presets?: DateFilterOption[];
|
|
30
|
+
operators?: DateFilterOption[];
|
|
31
|
+
units?: DateFilterOption[];
|
|
32
|
+
labels?: Partial<DateFilterLabels>;
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
declare function DateFilter({ value, onChange, presets, operators, units, labels, children, }: DateFilterProps): React.JSX.Element;
|
|
36
|
+
declare function DateFilterTrigger({ className, children, }: {
|
|
37
|
+
className?: string;
|
|
38
|
+
children?: ReactNode;
|
|
39
|
+
}): React.JSX.Element;
|
|
40
|
+
declare function DateFilterContent({ children, className, }: {
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
className?: string;
|
|
43
|
+
}): React.JSX.Element;
|
|
44
|
+
declare function DateFilterItem({ active, onSelect, children, }: {
|
|
45
|
+
active: boolean;
|
|
46
|
+
onSelect: () => void;
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
}): React.JSX.Element;
|
|
49
|
+
declare function DateFilterSeparator(): React.JSX.Element;
|
|
50
|
+
declare function DateFilterAll({ children }: {
|
|
51
|
+
children?: ReactNode;
|
|
52
|
+
}): React.JSX.Element;
|
|
53
|
+
declare function DateFilterPresets({ only }: {
|
|
54
|
+
only?: string[];
|
|
55
|
+
}): React.JSX.Element;
|
|
56
|
+
declare function DateFilterFixed({ children }: {
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}): React.JSX.Element;
|
|
59
|
+
declare function DateFilterRelative({ children }: {
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
}): React.JSX.Element;
|
|
62
|
+
|
|
63
|
+
declare function encodeDateFilter(filter: DateFilterValue): string | null;
|
|
64
|
+
|
|
65
|
+
declare function resolveRelativeRange(unit: DateFilterUnit, amount: number, includeCurrent: boolean, now?: Date, offsetAmount?: number, offsetUnit?: DateFilterUnit): {
|
|
66
|
+
start: Date;
|
|
67
|
+
end: Date;
|
|
68
|
+
} | null;
|
|
69
|
+
declare function formatRangePreview(range: {
|
|
70
|
+
start: Date;
|
|
71
|
+
end: Date;
|
|
72
|
+
}): string;
|
|
73
|
+
|
|
74
|
+
declare function summariseDateFilter(value: DateFilterValue, presets: DateFilterOption[], operators: DateFilterOption[], units: DateFilterOption[], labels: DateFilterLabels): string;
|
|
75
|
+
|
|
76
|
+
interface InfoFieldProps {
|
|
77
|
+
icon: LucideIcon;
|
|
78
|
+
label: string;
|
|
79
|
+
value: ReactNode;
|
|
80
|
+
iconClassName?: string;
|
|
81
|
+
className?: string;
|
|
82
|
+
}
|
|
83
|
+
declare function InfoField({ icon: Icon, label, value, iconClassName, className, }: InfoFieldProps): React.JSX.Element;
|
|
84
|
+
interface InfoFieldGroupProps {
|
|
85
|
+
children: ReactNode;
|
|
86
|
+
className?: string;
|
|
87
|
+
}
|
|
88
|
+
declare function InfoFieldGroup({ children, className }: InfoFieldGroupProps): React.JSX.Element;
|
|
89
|
+
|
|
90
|
+
interface LocalizedField {
|
|
91
|
+
name: string;
|
|
92
|
+
label: string;
|
|
93
|
+
type?: 'text' | 'textarea';
|
|
94
|
+
rows?: number;
|
|
95
|
+
}
|
|
96
|
+
interface LocalizedFieldsProps {
|
|
97
|
+
locales: string[];
|
|
98
|
+
localeLabels?: Record<string, string>;
|
|
99
|
+
fields: LocalizedField[];
|
|
100
|
+
values: Record<string, Record<string, string>>;
|
|
101
|
+
onChange: (field: string, locale: string, value: string) => void;
|
|
102
|
+
errors?: Record<string, string>;
|
|
103
|
+
defaultLocale?: string;
|
|
104
|
+
className?: string;
|
|
105
|
+
}
|
|
106
|
+
declare function LocalizedFields({ locales, localeLabels, fields, values, onChange, errors, defaultLocale, className, }: LocalizedFieldsProps): React.JSX.Element;
|
|
107
|
+
|
|
108
|
+
interface SectionHeaderProps {
|
|
109
|
+
icon?: ReactNode;
|
|
110
|
+
title: string;
|
|
111
|
+
description?: string;
|
|
112
|
+
control?: ReactNode;
|
|
113
|
+
className?: string;
|
|
114
|
+
}
|
|
115
|
+
declare function SectionHeader({ icon, title, description, control, className, }: SectionHeaderProps): React.JSX.Element;
|
|
116
|
+
|
|
117
|
+
interface SettingsCardProps extends SurfaceProps {
|
|
118
|
+
icon: LucideIcon;
|
|
119
|
+
iconClassName?: string;
|
|
120
|
+
title: string;
|
|
121
|
+
description: string;
|
|
122
|
+
control?: ReactNode;
|
|
123
|
+
children: ReactNode;
|
|
124
|
+
className?: string;
|
|
125
|
+
}
|
|
126
|
+
declare function SettingsCard({ icon: Icon, iconClassName, title, description, control, children, inset, className, }: SettingsCardProps): React.JSX.Element;
|
|
127
|
+
interface SettingsPanelProps extends SurfaceProps {
|
|
128
|
+
title?: string;
|
|
129
|
+
description?: string;
|
|
130
|
+
children: ReactNode;
|
|
131
|
+
className?: string;
|
|
132
|
+
}
|
|
133
|
+
declare function SettingsPanel({ title, description, children, inset, className, }: SettingsPanelProps): React.JSX.Element;
|
|
134
|
+
interface ToggleRowProps {
|
|
135
|
+
id: string;
|
|
136
|
+
label: string;
|
|
137
|
+
description?: string;
|
|
138
|
+
checked: boolean;
|
|
139
|
+
onChange: (checked: boolean) => void;
|
|
140
|
+
disabled?: boolean;
|
|
141
|
+
}
|
|
142
|
+
declare function ToggleRow({ id, label, description, checked, onChange, disabled, }: ToggleRowProps): React.JSX.Element;
|
|
143
|
+
|
|
144
|
+
interface StatCardProps extends SurfaceProps {
|
|
145
|
+
title: string;
|
|
146
|
+
value: ReactNode;
|
|
147
|
+
icon: LucideIcon;
|
|
148
|
+
iconClassName?: string;
|
|
149
|
+
trend?: number;
|
|
150
|
+
comparisonLabel?: string;
|
|
151
|
+
className?: string;
|
|
152
|
+
}
|
|
153
|
+
declare function StatCard({ title, value, icon: Icon, iconClassName, trend, comparisonLabel, inset, className, }: StatCardProps): React.JSX.Element;
|
|
154
|
+
interface StatsGridProps {
|
|
155
|
+
children: ReactNode;
|
|
156
|
+
className?: string;
|
|
157
|
+
}
|
|
158
|
+
declare function StatsGrid({ children, className }: StatsGridProps): React.JSX.Element;
|
|
159
|
+
|
|
160
|
+
declare function stepsForBreakpoint(steps: TourStep[], breakpoint: TourBreakpoint): TourStep[];
|
|
161
|
+
declare function resolveSteps(steps: TourStep[], isPresent: (target: string) => boolean): TourStep[];
|
|
162
|
+
declare function shouldStartTour(input: {
|
|
163
|
+
definition: TourDefinition;
|
|
164
|
+
seen: Record<string, number>;
|
|
165
|
+
resolvedStepCount: number;
|
|
166
|
+
force?: boolean;
|
|
167
|
+
}): boolean;
|
|
168
|
+
|
|
169
|
+
interface TourControllerValue {
|
|
170
|
+
startTour: (definition: TourDefinition, options?: {
|
|
171
|
+
force?: boolean;
|
|
172
|
+
}) => void;
|
|
173
|
+
}
|
|
174
|
+
declare function TourProvider({ children, seen, onProgress, labels, }: PropsWithChildren<{
|
|
175
|
+
seen: Record<string, number>;
|
|
176
|
+
onProgress: (progress: TourProgress) => void;
|
|
177
|
+
labels?: Partial<TourLabels>;
|
|
178
|
+
}>): ReactElement;
|
|
179
|
+
declare function useTourController(): TourControllerValue;
|
|
180
|
+
declare function useTour(definition: TourDefinition, options?: {
|
|
181
|
+
enabled?: boolean;
|
|
182
|
+
}): {
|
|
183
|
+
restart: () => void;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export { DateFilter, DateFilterAll, DateFilterContent, type DateFilterContextValue, DateFilterFixed, DateFilterItem, DateFilterLabels, DateFilterOption, type DateFilterPanel, DateFilterPresets, type DateFilterProps, DateFilterRelative, DateFilterSeparator, DateFilterTrigger, DateFilterUnit, DateFilterValue, InfoField, InfoFieldGroup, type InfoFieldGroupProps, type InfoFieldProps, type LocalizedField, LocalizedFields, type LocalizedFieldsProps, SectionHeader, type SectionHeaderProps, SettingsCard, type SettingsCardProps, SettingsPanel, type SettingsPanelProps, StatCard, type StatCardProps, StatsGrid, type StatsGridProps, ToggleRow, type ToggleRowProps, TourBreakpoint, TourDefinition, TourLabels, TourProgress, TourProvider, TourStep, encodeDateFilter, formatRangePreview, resolveRelativeRange, resolveSteps, shouldStartTour, stepsForBreakpoint, summariseDateFilter, useDateFilter, useTour, useTourController };
|