@maropost-ui/liquidsky-ui 0.1.80 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +105 -41
  2. package/dist/assets/raw-svg.d.ts +4 -0
  3. package/dist/components/MpSectionRail/types.d.ts +45 -0
  4. package/dist/components/TheAppShell/index.d.ts +1 -0
  5. package/dist/components/TheHeader/index.d.ts +3 -0
  6. package/dist/components/TheHeader/types.d.ts +68 -0
  7. package/dist/components/TheSearchBar/index.d.ts +3 -0
  8. package/dist/components/TheSearchBar/types.d.ts +8 -0
  9. package/dist/components/TheSearchBar/useTheSearchBar.d.ts +12 -0
  10. package/dist/components/TheUnifiedNavigation/index.d.ts +8 -4
  11. package/dist/components/TheUnifiedNavigation/marobase/navigation.d.ts +7 -0
  12. package/dist/components/TheUnifiedNavigation/marobase/types.d.ts +14 -0
  13. package/dist/components/TheUserDropdown/index.d.ts +3 -0
  14. package/dist/components/TheUserDropdown/useUserDropdownMenu.d.ts +12 -0
  15. package/dist/components/index.d.ts +12 -4
  16. package/dist/composables/index.d.ts +3 -0
  17. package/dist/composables/useHotkeys.d.ts +36 -0
  18. package/dist/composables/useLiquidSkyTheme.d.ts +13 -0
  19. package/dist/composables/useMpTestId.d.ts +5 -5
  20. package/dist/design-tokens/generated/tokens.d.ts +587 -0
  21. package/dist/directives/mpTestConfig.d.ts +2 -0
  22. package/dist/icons/index.d.ts +71 -0
  23. package/dist/icons/liquidSkyIconSet.d.ts +2 -0
  24. package/dist/icons/liquidSkyIcons.d.ts +55 -0
  25. package/dist/index.css +1 -1
  26. package/dist/index.d.ts +8 -1
  27. package/dist/index.js +19090 -15309
  28. package/dist/lib/davinci-orb/mark.d.ts +13 -0
  29. package/dist/themes/classic.d.ts +38 -0
  30. package/dist/themes/index.d.ts +157 -0
  31. package/dist/themes/marobase.d.ts +103 -0
  32. package/dist/themes/theme-sync.d.ts +38 -0
  33. package/dist/types/MpNotificationsMenuProps.d.ts +38 -0
  34. package/dist/types/TheUserDropdownProps.d.ts +46 -1
  35. package/dist/types/UnifiedNavigationProps.d.ts +11 -3
  36. package/dist/types/index.d.ts +2 -0
  37. package/dist/vuetify.d.ts +4 -40
  38. package/package.json +18 -7
  39. package/scripts/webpack-resolve.cjs +61 -0
package/README.md CHANGED
@@ -35,9 +35,10 @@ The following packages are required as peer dependencies:
35
35
  npm install @maropost-ui/liquidsky-ui
36
36
  ```
37
37
  ```typescript
38
- import { AppBreadcrumb } from '@maropost-ui/liquidsky-ui'
38
+ import { AppBreadcrumb, TheThemeSwitcher } from '@maropost-ui/liquidsky-ui'
39
39
  ```
40
40
 
41
+ Theme lives in `TheUserDropdown`: click **Theme** for Classic / Marobase. Light / Dark sun–moon controls appear on the right only for Marobase. Persist key is `liquidsky-theme`.
41
42
 
42
43
  ## Test identifiers (`v-mp-test`)
43
44
 
@@ -55,7 +56,6 @@ MP_TEST_COMPONENT_DEFAULTS.AppDialogWrapper.ids
55
56
 
56
57
  Storybook: **Directives → MpTest** (catalog of defaults).
57
58
 
58
-
59
59
  ------------------------------------------------------------------------
60
60
 
61
61
  ------------------------------------------------------------------------
@@ -155,67 +155,132 @@ You may also keep using **`v-btn`**, **`v-tooltip`**, etc., after Liquidsky is i
155
155
  -------------------------------------------------------------------------
156
156
 
157
157
 
158
- ## @maropost-ui/liquidsky-ui Local Development Guide
159
- Use these methods to test @maropost-ui/liquidsky-ui changes in your consuming project (e.g., commerce-frontend or commerce-backoffice) without publishing to npm. Both leverage npm's linking and packaging features for rapid iteration in your app workflow.
158
+ ## Local development in a consuming app
159
+
160
+ Use **`npm install`** for CI, teammates, and anything that should match production. Use **`npm link`** only when you are changing Liquidsky locally and want the app to pick up rebuilt `dist/` without publishing.
161
+
162
+ Liquidsky ships **Vuetify** as a dependency. Commerce apps typically do not declare `vuetify` themselves.
160
163
 
164
+ ### Webpack `vue.config.js` (required for Vue CLI apps)
161
165
 
166
+ Add this whether the app uses `npm install` or `npm link`. It keeps a single Vue copy and tells webpack where Vuetify is.
162
167
 
163
- ### 🚀 Method 1: npm link (Recommended for Active Development)
164
- Creates a symlink for instant hot-reloading of changes.
168
+ ```js
169
+ const path = require('path')
170
+ const { createLiquidskyWebpackResolve } = require('@maropost-ui/liquidsky-ui/webpack')
165
171
 
166
- > **Note:** This method does **not** work well with Webpack. If you are using Vite, this is the preferred approach. Otherwise, use Method 2.
172
+ const liquidskyResolve = createLiquidskyWebpackResolve(__dirname)
173
+
174
+ module.exports = {
175
+ transpileDependencies: ['@maropost-ui/liquidsky-ui'],
176
+ configureWebpack: {
177
+ resolve: {
178
+ ...liquidskyResolve,
179
+ alias: {
180
+ '@': path.resolve(__dirname, 'src'),
181
+ ...liquidskyResolve.alias,
182
+ },
183
+ },
184
+ },
185
+ }
186
+ ```
167
187
 
168
- #### Steps:
188
+ `@maropost-ui/liquidsky-ui/webpack` exists only in Liquidsky versions that include this helper. Install from this repo (pack / path) until that version is published.
169
189
 
170
- 1. **Clone the repository:**
171
- ```bash
172
- git clone <repo-url> liquidsky-frontend
173
- cd liquidsky-frontend
174
- git checkout main
175
- ```
190
+ ---
176
191
 
177
- 2. **Install dependencies and build the package:**
178
- ```bash
179
- npm install
180
- npm run dev
181
- ```
192
+ ### Method 1: `npm install` (normal / published / pack)
182
193
 
183
- 3. **Create a local npm link:**
184
- ```bash
185
- npm link
186
- ```
194
+ No `link:webpack`. No `--app`. npm hoists Vuetify into the app’s `node_modules`.
187
195
 
188
- 4. **In your consuming project (e.g., `commerce-frontend`):**
189
- ```bash
190
- cd /path/to/your/consuming-project
191
- npm link @maropost-ui/liquidsky-ui
192
- ```
196
+ **From the registry** (after the helper is published):
193
197
 
194
- Now, any changes you make in the `liquidsky-frontend` package will be reflected in your consuming project after rebuilding the library. This is useful for rapid development and testing across multiple projects locally.
198
+ ```bash
199
+ cd /path/to/maropost-frontend-app # or maropost-cloud-frontend / commerce-backoffice-frontend
200
+ npm install @maropost-ui/liquidsky-ui
201
+ ```
195
202
 
196
- ### 📦 Method 2: Local npm pack (For Stable Builds)
197
- Generates a distributable .tgz file for one-off installs.
203
+ **From this repo, without publishing:**
198
204
 
199
- #### Step 1: Clone and build the library
200
205
  ```bash
201
- git clone <repo-url> liquidsky-frontend
202
206
  cd liquidsky-frontend
203
- git checkout main
204
207
  npm install
205
208
  npm run build
209
+ npm pack
210
+ ```
211
+
212
+ ```bash
213
+ cd /path/to/maropost-frontend-app # or maropost-cloud-frontend / commerce-backoffice-frontend
214
+ npm unlink --no-save @maropost-ui/liquidsky-ui # only if you previously npm-linked
215
+ npm install /path/to/liquidsky-frontend/maropost-ui-liquidsky-ui-<version>.tgz
206
216
  ```
207
- #### Step 2: Create package
217
+
218
+ Prefer the `.tgz` over `npm install /path/to/liquidsky-frontend`. A folder install can still symlink and hit the same webpack issue as a repo-root `npm link`.
219
+
220
+ ---
221
+
222
+ ### Method 2: `npm link` (local Liquidsky changes)
223
+
224
+ **Do not `npm link` from this repo root in a Webpack app.** Webpack follows that symlink into Liquidsky’s `node_modules` and loads a second Vue.
225
+
226
+ #### Vite consumers
227
+
208
228
  ```bash
209
- npm pack
210
- Creates liquidsky-ui-<version>.tgz.
229
+ cd liquidsky-frontend
230
+ npm install
231
+ npm run dev
232
+ npm link
233
+ ```
234
+
235
+ ```bash
236
+ cd /path/to/your-vite-app
237
+ npm link @maropost-ui/liquidsky-ui
238
+ ```
239
+
240
+ #### Webpack consumers (maropost-frontend-app / maropost-cloud-frontend / commerce-backoffice-frontend)
241
+
242
+ `--app` is **one-time setup** for that app (creates `node_modules/vuetify` if it is missing). You do not pass the path on later rebuilds.
243
+
244
+ The `--` after `npm run link:webpack` forwards flags to the script.
245
+
246
+ **Once per webpack app:**
247
+
248
+ ```bash
249
+ cd liquidsky-frontend
250
+ npm install
251
+ npm run build
252
+ npm run link:webpack -- --app /path/to/maropost-frontend-app
253
+ # or
254
+ npm run link:webpack -- --app /path/to/maropost-cloud-frontend
255
+ # or
256
+ npm run link:webpack -- --app /path/to/commerce-backoffice-frontend
211
257
  ```
212
258
 
213
- #### Step 3: Install in consuming project
214
259
  ```bash
215
- cd /path/to/commerce-backoffice # or your project
216
- npm install ../../path/to/liquidsky-frontend/liquidsky-ui-<version>.tgz
260
+ cd /path/to/maropost-frontend-app # or maropost-cloud-frontend / commerce-backoffice-frontend
261
+ npm unlink --no-save @maropost-ui/liquidsky-ui # if you previously linked the repo root
262
+ npm link @maropost-ui/liquidsky-ui
217
263
  ```
218
264
 
265
+ If a **repo-root** link is still registered globally:
266
+
267
+ ```bash
268
+ npm unlink -g @maropost-ui/liquidsky-ui
269
+ ```
270
+
271
+ **Every later rebuild** (no `--app`):
272
+
273
+ ```bash
274
+ cd liquidsky-frontend
275
+ npm run link:webpack
276
+ # or, rebuild on save:
277
+ npm run link:webpack:watch
278
+ ```
279
+
280
+ Then restart or refresh the webpack app. `link:webpack` copies `dist/` to `../.liquidsky-ui-link` (a folder with no Liquidsky Vue) and runs `npm link` from there.
281
+
282
+ Use `--app` again only if you clone a new consumer, delete `node_modules`, or Vuetify disappears from the app.
283
+
219
284
  ------------------------------------------------------------------------
220
285
 
221
286
 
@@ -318,4 +383,3 @@ stories/
318
383
  ```
319
384
 
320
385
 
321
-
@@ -0,0 +1,4 @@
1
+ declare module '*.svg?raw' {
2
+ const source: string;
3
+ export default source;
4
+ }
@@ -0,0 +1,45 @@
1
+ import type { RouteLocationRaw } from 'vue-router';
2
+ export interface MpSectionRailItem {
3
+ slug: string;
4
+ label: string;
5
+ /** Lucide icon name (kebab-case). Omit for text-only rows (Settings flavor). */
6
+ icon?: string;
7
+ to: RouteLocationRaw;
8
+ /** Route names that keep this item highlighted (the section's children/editors). */
9
+ match?: string[];
10
+ /** Optional count chip shown at the end of the row. */
11
+ count?: number;
12
+ /** Renders an external-link glyph after the label. */
13
+ external?: boolean;
14
+ }
15
+ export interface MpSectionRailGroup {
16
+ /** Optional uppercase group heading. */
17
+ title?: string;
18
+ items: MpSectionRailItem[];
19
+ }
20
+ export interface MpSectionRailSwitchOption {
21
+ id: string;
22
+ label: string;
23
+ caption?: string;
24
+ icon?: string;
25
+ }
26
+ export interface MpSectionRailProps {
27
+ /** Accessible name for the rail's nav landmark. */
28
+ ariaLabel: string;
29
+ groups: MpSectionRailGroup[];
30
+ /** Plain heading (module flavor, e.g. "Settings"). */
31
+ title?: string;
32
+ backTo?: RouteLocationRaw;
33
+ backLabel?: string;
34
+ /** Entity identity card (entity flavor, e.g. a store). */
35
+ identity?: {
36
+ name: string;
37
+ caption?: string;
38
+ icon?: string;
39
+ };
40
+ /** Other entities the user can jump to; renders the switcher menu on the identity card. */
41
+ switcherOptions?: MpSectionRailSwitchOption[];
42
+ switcherLabel?: string;
43
+ searchable?: boolean;
44
+ searchPlaceholder?: string;
45
+ }
@@ -0,0 +1 @@
1
+ export { default } from './TheAppShell.vue';
@@ -0,0 +1,3 @@
1
+ export { default } from './TheHeader.vue';
2
+ export { default as ClassicHeader } from './Classic/TheHeader.vue';
3
+ export { default as MarobaseHeader } from './Marobase/TheHeader.vue';
@@ -0,0 +1,68 @@
1
+ import type { NotificationIconProps } from '../../types/NotificationIconProps';
2
+ import type { MpNotificationsMenuProps } from '../../types/MpNotificationsMenuProps';
3
+ import type { NotificationItem } from '../../types/TheNotificationDrawerProps';
4
+ import type { MpTestIdProps } from '../../types/MpTestIdProps';
5
+ export type CreateNewMenuIcon = 'dashboard' | 'email-campaign' | 'segment' | 'automation' | 'contact-list';
6
+ /** A destination shown in the Marobase header's Create new menu. */
7
+ export type CreateNewMenuItem = {
8
+ /** Stable key for rendering the item. */
9
+ id: string;
10
+ title: string;
11
+ description?: string;
12
+ /** Icon rendered by the library. */
13
+ icon?: CreateNewMenuIcon;
14
+ /** Optional keyboard hint displayed at the end of the item. */
15
+ shortcut?: string;
16
+ /** Application-owned navigation or creation action. */
17
+ onClick: () => void;
18
+ };
19
+ export type MpNotificationsMenuBindings = MpNotificationsMenuProps & {
20
+ onOpen?: () => void;
21
+ onClose?: () => void;
22
+ onSeeAll?: () => void;
23
+ onMarkAllRead?: () => void;
24
+ onNotificationClick?: (notification: NotificationItem) => void;
25
+ onDownload?: (notification: NotificationItem) => void;
26
+ onRetry?: () => void;
27
+ onLoadMore?: () => void;
28
+ };
29
+ /** Application-owned permissions and navigation for Liquidsky's header controls. */
30
+ export type HeaderActions = {
31
+ /** Items for the Marobase Create new (+) menu. When omitted, + retains its What's new action. */
32
+ createNewItems?: CreateNewMenuItem[];
33
+ showSettings?: boolean;
34
+ settingsHref?: string;
35
+ onSettingsClick?: (event: MouseEvent) => void;
36
+ onDaVinciClick: () => void;
37
+ onWhatsNewClick: () => void;
38
+ helpCenterUrl?: string;
39
+ raiseTicketUrl?: string;
40
+ };
41
+ export type TheHeaderProps = {
42
+ /** Opt into the theme's utility controls in place of the default timezone. */
43
+ actions?: HeaderActions;
44
+ /** notification count e.g. 5 */
45
+ notificationCount?: number;
46
+ /** timezone e.g. UTC, EST, etc. */
47
+ timezone?: string;
48
+ /** route to preferences : on click to timezone it will open the preferences page*/
49
+ routeToPreferences?: string;
50
+ /** is page loading e.g. true or false */
51
+ isPageLoading: boolean;
52
+ /** toggle left menu e.g. true or false */
53
+ toggleLeftMenu: () => void;
54
+ /** user menu items e.g. [{ title: "Profile", icon: "mdi-account", action: () => {} }, { title: "Settings", icon: "mdi-cog", action: () => {} }] */
55
+ userMenuItems?: any[];
56
+ /** username e.g. John Doe */
57
+ username?: string;
58
+ /** logout e.g. () => {} */
59
+ logout?: () => void;
60
+ /** account id e.g. 20001 */
61
+ accountId?: string | number;
62
+ /** show app bar nav icon e.g. true or false */
63
+ hideAppBarNavIcon?: boolean;
64
+ /** notification icon props e.g. { icon: "mdi-bell", color: "primary" } */
65
+ notificationIconProps?: NotificationIconProps;
66
+ /** Marobase notification menu data, states, and application-owned action handlers. */
67
+ notificationMenuProps?: MpNotificationsMenuBindings;
68
+ } & MpTestIdProps;
@@ -0,0 +1,3 @@
1
+ export { default } from './TheSearchBar.vue';
2
+ export { default as ClassicSearchBar } from './Classic/TheSearchBar.vue';
3
+ export { default as MarobaseSearchBar } from './Marobase/TheSearchBar.vue';
@@ -0,0 +1,8 @@
1
+ import type { MpTestIdProps } from '../../types/MpTestIdProps';
2
+ export type TheSearchBarProps = {
3
+ /** The name of the query parameter to use for search (defaults to 'q') */
4
+ queryParamName?: string;
5
+ show?: boolean;
6
+ placeholder?: string;
7
+ containerClass?: string;
8
+ } & MpTestIdProps;
@@ -0,0 +1,12 @@
1
+ import type { TheSearchBarProps } from './types';
2
+ export declare function useTheSearchBar(props: TheSearchBarProps): {
3
+ mpTestId: import("vue").ComputedRef<string>;
4
+ keyword: import("vue").Ref<string | undefined, string | undefined>;
5
+ clearSearch: () => void;
6
+ searchPlaceholder: import("vue").ComputedRef<string>;
7
+ showSearchBar: import("vue").ComputedRef<boolean>;
8
+ handleSearchKeyup: (event: KeyboardEvent) => void;
9
+ isFocused: import("vue").Ref<boolean, boolean>;
10
+ onSearchFocus: () => void;
11
+ onSearchBlur: () => void;
12
+ };
@@ -1,5 +1,9 @@
1
1
  export { default as TheUnifiedNavigation } from './TheUnifiedNavigation.vue';
2
- export { default as UnifiedNavigationBlock } from './UnifiedNavigationBlock.vue';
3
- export { default as NavigationToggleButton } from './NavigationToggleButton.vue';
4
- export { default as SubMenuDialog } from './SubMenuDialog.vue';
5
- export { default as UnifiedNavigationNode } from './UnifiedNavigationNode.vue';
2
+ export { default as ClassicUnifiedNavigation } from './classic/ClassicUnifiedNavigation.vue';
3
+ export { default as UnifiedNavigationBlock } from './classic/UnifiedNavigationBlock.vue';
4
+ export { default as NavigationToggleButton } from './classic/NavigationToggleButton.vue';
5
+ export { default as SubMenuDialog } from './classic/SubMenuDialog.vue';
6
+ export { default as UnifiedNavigationNode } from './classic/UnifiedNavigationNode.vue';
7
+ export { default as MarobaseSidebar } from './marobase/MarobaseSidebar.vue';
8
+ export type { MarobaseSidebarProps, AppSidebarProps } from './marobase/types';
9
+ export { default as TheAppSidebar } from './marobase/MarobaseSidebar.vue';
@@ -0,0 +1,7 @@
1
+ import type { UnifiedNavigationItem } from '../../../types/UnifiedNavigationProps';
2
+ export type SidebarSection = {
3
+ key: string;
4
+ items: UnifiedNavigationItem[];
5
+ };
6
+ export declare function sidebarSections(items: UnifiedNavigationItem[]): SidebarSection[];
7
+ export declare function scopedPath(item: UnifiedNavigationItem, accountId: string): string | undefined;
@@ -0,0 +1,14 @@
1
+ import type { SidebarGetStarted, UnifiedNavigationProps } from '../../../types/UnifiedNavigationProps';
2
+ export interface MarobaseSidebarProps extends UnifiedNavigationProps {
3
+ modelValue?: boolean;
4
+ temporary?: boolean;
5
+ width?: number;
6
+ railWidth?: number;
7
+ brandLabel?: string;
8
+ getStarted?: SidebarGetStarted;
9
+ /** Optional controlled section. When omitted, enableStoreMenu supplies route state. */
10
+ activeSection?: 'store' | null;
11
+ sectionWidth?: number;
12
+ }
13
+ /** Previous public name for MarobaseSidebarProps. */
14
+ export type AppSidebarProps = MarobaseSidebarProps;
@@ -0,0 +1,3 @@
1
+ export { default as TheUserDropdown } from './TheUserDropdown.vue';
2
+ export { default as ClassicUserDropdown } from './classic/ClassicUserDropdown.vue';
3
+ export { default as MarobaseUserDropdown } from './marobase/MarobaseUserDropdown.vue';
@@ -0,0 +1,12 @@
1
+ import type { TheUserDropdownProps } from '../../types/TheUserDropdownProps';
2
+ import type { ThemeAppearance } from '../../themes';
3
+ export declare function userInitialsFromName(username: string | undefined): string;
4
+ export declare function useUserDropdownMenu(props: TheUserDropdownProps, emit: (event: 'logout') => void): {
5
+ mpTestId: import("vue").ComputedRef<string>;
6
+ isMenuOpen: import("vue").Ref<boolean, boolean>;
7
+ family: import("vue").ComputedRef<import("../../themes").ThemeFamily>;
8
+ userInitials: import("vue").ComputedRef<string>;
9
+ appearanceToggle: import("vue").WritableComputedRef<ThemeAppearance, ThemeAppearance | ThemeAppearance[] | null>;
10
+ setFamily: (next: import("../../themes").ThemeFamily) => void;
11
+ onClickLogoutHandler: () => void;
12
+ };
@@ -22,15 +22,23 @@ export { default as AppTooltip } from "./AppTooltip.vue";
22
22
  export { default as AppGridTable } from "./AppGridTable.vue";
23
23
  export { default as TheAccountDropdown } from "./TheAccountDropdown.vue";
24
24
  export { default as TheAppsDropdown } from "./TheAppsDropdown.vue";
25
- export { default as TheHeader } from "./TheHeader.vue";
25
+ export { default as TheHeader } from "./TheHeader";
26
+ export type { CreateNewMenuIcon, CreateNewMenuItem, HeaderActions, MpNotificationsMenuBindings, TheHeaderProps } from './TheHeader/types';
27
+ export { default as TheAppShell } from "./TheAppShell";
26
28
  export { default as TheNavigation } from "./TheNavigation.vue";
27
29
  export { default as TheNotificationDrawer } from "./TheNotificationDrawer.vue";
28
30
  export { default as TheNotificationIcon } from "./TheNotificationIcon.vue";
29
- export { default as TheSearchBar } from "./TheSearchBar.vue";
31
+ export { default as MpNotificationsMenu } from "./MpNotificationsMenu.vue";
32
+ export { default as TheSearchBar } from "./TheSearchBar";
30
33
  export { default as TheSecondaryNavigation } from "./TheSecondaryNavigation.vue";
34
+ export { default as MpSectionRail } from './MpSectionRail/MpSectionRail.vue';
35
+ export { default as StoreSectionRail } from './MpSectionRail/StoreSectionRail.vue';
36
+ export type { MpSectionRailProps, MpSectionRailItem, MpSectionRailGroup, MpSectionRailSwitchOption } from './MpSectionRail/types';
37
+ export { default as TheThemeSwitcher } from "./TheThemeSwitcher.vue";
31
38
  export { default as TheTimezone } from "./TheTimezone/TheTimezone.vue";
32
- export { default as TheUserDropdown } from "./TheUserDropdown.vue";
33
- export { TheUnifiedNavigation } from "./TheUnifiedNavigation";
39
+ export { TheUserDropdown, MarobaseUserDropdown } from "./TheUserDropdown";
40
+ export { TheUnifiedNavigation, MarobaseSidebar, TheAppSidebar } from "./TheUnifiedNavigation";
41
+ export type { MarobaseSidebarProps, AppSidebarProps } from "./TheUnifiedNavigation";
34
42
  export { default as AlertModal } from "./AlertModal.vue";
35
43
  export { default as TheOnboardingBanner } from "./TheOnboardingBanner.vue";
36
44
  export { default as TheOnboardingScreenChecklists } from "./TheOnboardingScreenChecklists.vue";
@@ -6,7 +6,10 @@ export { default as useValidation } from "./useValidation";
6
6
  export { default as useClipboard } from "./useClipboard";
7
7
  export { default as useDebounce } from "./useDebounce";
8
8
  export { default as useEmoji } from "./useEmoji";
9
+ export { default as useHotkeys } from "./useHotkeys";
10
+ export type { HotkeyBinding, UseHotkeysOptions } from "./useHotkeys";
9
11
  export { default as toRefs } from "./toRefs";
10
12
  export { default as useUnitConversion } from "./useUnitConversion";
11
13
  export { default as useTimezoneTime } from "./useCalculateTime";
12
14
  export { default as useMpTestId, resolveMpTestId } from "./useMpTestId";
15
+ export { default as useLiquidSkyTheme, resetLiquidSkyThemeForTests } from "./useLiquidSkyTheme";
@@ -0,0 +1,36 @@
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ export type HotkeyBinding = {
3
+ key: string;
4
+ handler: (event: KeyboardEvent) => void;
5
+ };
6
+ export type UseHotkeysOptions = {
7
+ /** Reactively enables or disables all bindings. */
8
+ enabled?: MaybeRefOrGetter<boolean>;
9
+ /** Allow shortcuts while typing in inputs, textareas, selects, or editable content. */
10
+ allowInEditable?: boolean;
11
+ /** Ignore key-repeat events. */
12
+ ignoreRepeat?: boolean;
13
+ /** Prevent the browser's default action when a binding matches. */
14
+ preventDefault?: boolean;
15
+ };
16
+ /**
17
+ * @description Listen for case-insensitive, unmodified keyboard shortcuts and fire matching handlers.
18
+ * Bindings and the enabled state may be reactive. By default, shortcuts are ignored while the
19
+ * user is typing, during IME composition, when modifier keys are held, and for repeated keydown
20
+ * events. The window listener is registered and removed with the owning component lifecycle.
21
+ *
22
+ * @example
23
+ * import { computed, ref } from 'vue'
24
+ * import { useHotkeys } from '@maropost-ui/liquidsky-ui'
25
+ *
26
+ * const menuOpen = ref(false)
27
+ * const bindings = computed(() => [
28
+ * { key: 'D', handler: () => router.push('/dashboard') },
29
+ * { key: 'E', handler: () => router.push('/campaigns/new') },
30
+ * ])
31
+ *
32
+ * useHotkeys(bindings, { enabled: menuOpen })
33
+ */
34
+ export default function useHotkeys(bindings: MaybeRefOrGetter<HotkeyBinding[]>, options?: UseHotkeysOptions): {
35
+ handleKeydown: (event: KeyboardEvent) => void;
36
+ };
@@ -0,0 +1,13 @@
1
+ import { type LiquidSkyThemeName, type ThemeAppearance, type ThemeFamily } from '../themes';
2
+ export declare function resetLiquidSkyThemeForTests(): void;
3
+ export default function useLiquidSkyTheme(options?: {
4
+ persist?: boolean;
5
+ storageKey?: string;
6
+ }): {
7
+ themeName: import("vue").Ref<LiquidSkyThemeName, LiquidSkyThemeName>;
8
+ family: import("vue").ComputedRef<ThemeFamily>;
9
+ appearance: import("vue").ComputedRef<ThemeAppearance>;
10
+ setTheme: (name: LiquidSkyThemeName) => void;
11
+ setFamily: (next: ThemeFamily) => void;
12
+ setAppearance: (next: ThemeAppearance) => void;
13
+ };
@@ -1,13 +1,13 @@
1
1
  import { type MpTestBindingObject } from '../directives/MpTest';
2
+ import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
2
3
  /**
3
4
  * @deprecated Prefer `resolveMpTestBinding` / `v-mp-test`.
4
5
  * Legacy `(defaultId, testId?, testIdSuffix?)` still supported.
5
6
  */
6
7
  export declare function resolveMpTestId(defaultIdOrBinding: string | MpTestBindingObject, testId?: string, testIdSuffix?: string): string;
7
8
  /**
8
- * @deprecated Use `v-mp-test="MP_TEST_IDS.*"` or
9
- * `v-mp-test="{ action, module, suffix }"`.
9
+ * @deprecated Prefer `v-mp-test="MP_TEST_IDS.*"` or
10
+ * `v-mp-test="{ action, module, suffix }"`. This compatibility wrapper remains
11
+ * available for themed components and consumers using the legacy test-id props.
10
12
  */
11
- export default function useMpTestId(_defaultId: string, _testId?: unknown, _testIdSuffix?: unknown): {
12
- readonly value: string;
13
- };
13
+ export default function useMpTestId(defaultId: string, testId?: MaybeRefOrGetter<string | undefined>, testIdSuffix?: MaybeRefOrGetter<string | undefined>): ComputedRef<string>;