@makolabs/ripple 3.1.1 → 3.3.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.
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
3
|
import { buildTestId } from '../../helper/testid.js';
|
|
4
|
-
import { Color } from '../../variants.js';
|
|
4
|
+
import { Color, Size } from '../../variants.js';
|
|
5
5
|
import { fade } from 'svelte/transition';
|
|
6
6
|
import { quintOut } from 'svelte/easing';
|
|
7
|
+
import Button from '../../button/Button.svelte';
|
|
7
8
|
import type { AlertProps, VariantColors } from '../../index.js';
|
|
8
9
|
|
|
9
10
|
let {
|
|
@@ -11,7 +12,7 @@
|
|
|
11
12
|
message,
|
|
12
13
|
color = Color.DEFAULT,
|
|
13
14
|
onclose,
|
|
14
|
-
|
|
15
|
+
actions,
|
|
15
16
|
icon: Icon,
|
|
16
17
|
class: className = '',
|
|
17
18
|
testId
|
|
@@ -21,6 +22,9 @@
|
|
|
21
22
|
onclose?.();
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
// Container chrome: bg-{c}-50 + border-{c}-200 + body text-{c}-800.
|
|
26
|
+
// Title and icon get their own steps for stronger hierarchy:
|
|
27
|
+
// title → text-{c}-900 (darker than body), icon circle → bg-{c}-100 / text-{c}-700.
|
|
24
28
|
const colorClasses: Record<VariantColors, string> = {
|
|
25
29
|
[Color.DEFAULT]: 'bg-default-50 border-default-200 text-default-800',
|
|
26
30
|
[Color.PRIMARY]: 'bg-primary-50 border-primary-200 text-primary-800',
|
|
@@ -30,28 +34,79 @@
|
|
|
30
34
|
[Color.WARNING]: 'bg-warning-50 border-warning-200 text-warning-800',
|
|
31
35
|
[Color.DANGER]: 'bg-danger-50 border-danger-200 text-danger-800'
|
|
32
36
|
};
|
|
37
|
+
|
|
38
|
+
const titleColorClasses: Record<VariantColors, string> = {
|
|
39
|
+
[Color.DEFAULT]: 'text-default-900',
|
|
40
|
+
[Color.PRIMARY]: 'text-primary-900',
|
|
41
|
+
[Color.SECONDARY]: 'text-secondary-900',
|
|
42
|
+
[Color.INFO]: 'text-info-900',
|
|
43
|
+
[Color.SUCCESS]: 'text-success-900',
|
|
44
|
+
[Color.WARNING]: 'text-warning-900',
|
|
45
|
+
[Color.DANGER]: 'text-danger-900'
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const iconCircleClasses: Record<VariantColors, string> = {
|
|
49
|
+
[Color.DEFAULT]: 'bg-default-100 text-default-700',
|
|
50
|
+
[Color.PRIMARY]: 'bg-primary-100 text-primary-700',
|
|
51
|
+
[Color.SECONDARY]: 'bg-secondary-100 text-secondary-700',
|
|
52
|
+
[Color.INFO]: 'bg-info-100 text-info-700',
|
|
53
|
+
[Color.SUCCESS]: 'bg-success-100 text-success-700',
|
|
54
|
+
[Color.WARNING]: 'bg-warning-100 text-warning-700',
|
|
55
|
+
[Color.DANGER]: 'bg-danger-100 text-danger-700'
|
|
56
|
+
};
|
|
33
57
|
</script>
|
|
34
58
|
|
|
35
59
|
<div
|
|
36
60
|
role="alert"
|
|
37
|
-
class={cn('relative rounded-lg border p-4', colorClasses[color], className)}
|
|
61
|
+
class={cn('relative rounded-lg border p-4 shadow-sm', colorClasses[color], className)}
|
|
38
62
|
data-testid={buildTestId('alert', undefined, testId)}
|
|
39
63
|
transition:fade={{ duration: 1000, easing: quintOut }}
|
|
40
64
|
>
|
|
41
|
-
<div class="flex items-
|
|
65
|
+
<div class="flex items-center justify-between gap-4">
|
|
42
66
|
{#if Icon}
|
|
43
|
-
<
|
|
67
|
+
<div
|
|
68
|
+
class={cn(
|
|
69
|
+
'flex h-10 w-10 shrink-0 items-center justify-center rounded-full',
|
|
70
|
+
iconCircleClasses[color]
|
|
71
|
+
)}
|
|
72
|
+
aria-hidden="true"
|
|
73
|
+
data-testid={buildTestId('alert', 'icon', testId)}
|
|
74
|
+
>
|
|
75
|
+
<Icon class="h-5 w-5" />
|
|
76
|
+
</div>
|
|
44
77
|
{/if}
|
|
45
|
-
<div class="flex-1">
|
|
78
|
+
<div class="min-w-0 flex-1">
|
|
46
79
|
{#if title}
|
|
47
|
-
<h4
|
|
80
|
+
<h4
|
|
81
|
+
class={cn('font-semibold', titleColorClasses[color])}
|
|
82
|
+
data-testid={buildTestId('alert', 'title', testId)}
|
|
83
|
+
>
|
|
84
|
+
{title}
|
|
85
|
+
</h4>
|
|
48
86
|
{/if}
|
|
49
87
|
<p class="text-sm" data-testid={buildTestId('alert', 'message', testId)}>{message}</p>
|
|
50
88
|
</div>
|
|
89
|
+
{#if actions && actions.length > 0}
|
|
90
|
+
<div
|
|
91
|
+
class="flex shrink-0 items-center gap-2"
|
|
92
|
+
data-testid={buildTestId('alert', 'actions', testId)}
|
|
93
|
+
>
|
|
94
|
+
{#each actions as action, i (action.label + i)}
|
|
95
|
+
<Button
|
|
96
|
+
size={Size.SM}
|
|
97
|
+
variant={action.variant ?? 'solid'}
|
|
98
|
+
color={action.color ?? color}
|
|
99
|
+
onclick={() => action.onclick?.()}
|
|
100
|
+
>
|
|
101
|
+
{action.label}
|
|
102
|
+
</Button>
|
|
103
|
+
{/each}
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
51
106
|
{#if onclose}
|
|
52
107
|
<button
|
|
53
108
|
type="button"
|
|
54
|
-
class="hover:bg-default-200/20
|
|
109
|
+
class="hover:bg-default-200/20 shrink-0 cursor-pointer rounded-md p-1"
|
|
55
110
|
onclick={handleClose}
|
|
56
111
|
aria-label="Close alert"
|
|
57
112
|
data-testid={buildTestId('alert', 'close', testId)}
|
|
@@ -66,7 +121,4 @@
|
|
|
66
121
|
</button>
|
|
67
122
|
{/if}
|
|
68
123
|
</div>
|
|
69
|
-
{#if footer}
|
|
70
|
-
{@render footer()}
|
|
71
|
-
{/if}
|
|
72
124
|
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type { ModalProps } from './modal/modal-types.js';
|
|
|
28
28
|
export type { ConfirmDialogProps } from './modal/confirm-dialog-types.js';
|
|
29
29
|
export type { DrawerProps } from './drawer/drawer-types.js';
|
|
30
30
|
export type { DropdownItem, DropSection, DropHeaderConfig, DropdownMenuProps, SelectItem, SelectProps } from './elements/dropdown/dropdown-types.js';
|
|
31
|
-
export type { CardProps, AlertProps, MetricDetail, MetricCardProps } from './layout/card/card-types.js';
|
|
31
|
+
export type { CardProps, AlertProps, AlertAction, MetricDetail, MetricCardProps } from './layout/card/card-types.js';
|
|
32
32
|
export type { DataRow, KeyType, StatusType, TableColumn, SortDirection, SortState, TableProps } from './layout/table/table-types.js';
|
|
33
33
|
export type { BreadcrumbItem, BreadcrumbsProps, PageHeaderProps } from './header/header-types.js';
|
|
34
34
|
export type { TabItem, TabProps, TabsGroupProps, TabContentProps } from './layout/tabs/tabs-types.js';
|
|
@@ -143,7 +143,7 @@ export { CompactFilters, FilterPopover, FilterBar, syncFiltersToUrl } from './fi
|
|
|
143
143
|
export * from './file-browser/index.js';
|
|
144
144
|
export * from './adapters/storage/index.js';
|
|
145
145
|
export * from './adapters/ai/index.js';
|
|
146
|
-
export { getUserDisplayName, getUserInitials } from './user-management/user-management.js';
|
|
146
|
+
export { getUserDisplayName, getUserInitials, adaptUserManagementRemote } from './user-management/user-management.js';
|
|
147
147
|
export { default as UserManagement } from './user-management/UserManagement.svelte';
|
|
148
148
|
export { default as UserTable } from './user-management/UserTable.svelte';
|
|
149
149
|
export { default as UserModal } from './user-management/UserModal.svelte';
|
package/dist/index.js
CHANGED
|
@@ -145,7 +145,7 @@ export * from './adapters/ai/index.js';
|
|
|
145
145
|
// ============================================================================
|
|
146
146
|
// User Management Helper Functions
|
|
147
147
|
// ============================================================================
|
|
148
|
-
export { getUserDisplayName, getUserInitials } from './user-management/user-management.js';
|
|
148
|
+
export { getUserDisplayName, getUserInitials, adaptUserManagementRemote } from './user-management/user-management.js';
|
|
149
149
|
// ============================================================================
|
|
150
150
|
// User Management Components
|
|
151
151
|
// ============================================================================
|
|
@@ -73,6 +73,26 @@ export type CardProps = {
|
|
|
73
73
|
loading?: boolean;
|
|
74
74
|
testId?: string;
|
|
75
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Button-style action attached to an `<Alert>` (e.g. "Mark as Shipped",
|
|
78
|
+
* "Upgrade now"). Rendered inline on the right side of the alert,
|
|
79
|
+
* between the message and the optional close button.
|
|
80
|
+
*
|
|
81
|
+
* The same shape as `ActivityItemAction` — consumers building both
|
|
82
|
+
* activity feeds and alerts only need to learn one action contract.
|
|
83
|
+
*/
|
|
84
|
+
export type AlertAction = {
|
|
85
|
+
label: string;
|
|
86
|
+
onclick?: () => void;
|
|
87
|
+
/**
|
|
88
|
+
* Override the action button's color. Defaults to the parent
|
|
89
|
+
* `<Alert>`'s `color` so the CTA visually anchors to the banner
|
|
90
|
+
* (e.g. a warning alert gets warning-colored buttons).
|
|
91
|
+
*/
|
|
92
|
+
color?: VariantColors;
|
|
93
|
+
/** Optional ripple button variant. @default 'solid' */
|
|
94
|
+
variant?: 'solid' | 'outline' | 'ghost' | 'link';
|
|
95
|
+
};
|
|
76
96
|
/**
|
|
77
97
|
* Props for `<Alert>` — a prominent inline banner for success / warning /
|
|
78
98
|
* error / info messages. Use at the top of a page or above a form. For
|
|
@@ -86,12 +106,14 @@ export type CardProps = {
|
|
|
86
106
|
*
|
|
87
107
|
* @example
|
|
88
108
|
* ```svelte
|
|
89
|
-
* <!-- Dismissable with
|
|
90
|
-
* <Alert
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
109
|
+
* <!-- Dismissable with an inline action -->
|
|
110
|
+
* <Alert
|
|
111
|
+
* color="warning"
|
|
112
|
+
* title="Ready for Shipment"
|
|
113
|
+
* message="Payment complete. Notify supplier when dispatched."
|
|
114
|
+
* actions={[{ label: 'Mark as Shipped', onclick: openShipModal }]}
|
|
115
|
+
* onclose={() => {}}
|
|
116
|
+
* />
|
|
95
117
|
* ```
|
|
96
118
|
*/
|
|
97
119
|
export type AlertProps = {
|
|
@@ -104,8 +126,12 @@ export type AlertProps = {
|
|
|
104
126
|
class?: ClassValue;
|
|
105
127
|
/** When provided, renders a × dismiss button. */
|
|
106
128
|
onclose?: () => void;
|
|
107
|
-
/**
|
|
108
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Inline action buttons rendered on the right side of the alert,
|
|
131
|
+
* between the message and the close button. Each action defaults
|
|
132
|
+
* to the alert's `color` and `variant: 'solid'`.
|
|
133
|
+
*/
|
|
134
|
+
actions?: AlertAction[];
|
|
109
135
|
/** Override the default color-appropriate icon. */
|
|
110
136
|
icon?: Component;
|
|
111
137
|
testId?: string;
|
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
* User Management Utilities
|
|
3
3
|
* Helper functions for user management
|
|
4
4
|
*/
|
|
5
|
-
import type { User } from '../index.js';
|
|
5
|
+
import type { User, UserManagementAdapter } from '../index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Wires a `*.remote.ts` module (typically `export * from
|
|
8
|
+
* '@makolabs/ripple/funcs/user-management.remote'`) to the strictly-typed
|
|
9
|
+
* `UserManagementAdapter` shape.
|
|
10
|
+
*
|
|
11
|
+
* Why this exists: SvelteKit ≥ 2.56 captures the inner async function's
|
|
12
|
+
* `Promise<X>` as `Output` in `RemoteCommand`'s call signature, so
|
|
13
|
+
* `command('unchecked', async (): Promise<X> => …)` types as
|
|
14
|
+
* `RemoteCommand<I, Promise<X>>` whose call returns `Promise<Promise<X>>`
|
|
15
|
+
* even though at runtime it resolves correctly to `Promise<X>`. That
|
|
16
|
+
* spurious extra wrap makes a direct `import * as adapter from
|
|
17
|
+
* './foo.remote'` reject the `UserManagementAdapter` assignment.
|
|
18
|
+
*
|
|
19
|
+
* The helper performs an `as unknown as` coercion in one place so
|
|
20
|
+
* consumers don't scatter casts in their pages, and so the workaround
|
|
21
|
+
* stays discoverable. Once SvelteKit fixes `RemoteCommand` to use
|
|
22
|
+
* `Awaited<Output>`, this helper becomes a transparent pass-through.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // src/routes/+page.svelte
|
|
27
|
+
* import { adaptUserManagementRemote } from '@makolabs/ripple';
|
|
28
|
+
* import * as remote from './users.remote';
|
|
29
|
+
* const adapter = adaptUserManagementRemote(remote);
|
|
30
|
+
* <UserManagement {adapter} {roles} />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function adaptUserManagementRemote<T>(remote: T): UserManagementAdapter;
|
|
6
34
|
export declare function getUserDisplayName(user: User | null): string;
|
|
7
35
|
export declare function getUserInitials(user: User | null): string;
|
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
* User Management Utilities
|
|
3
3
|
* Helper functions for user management
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* Wires a `*.remote.ts` module (typically `export * from
|
|
7
|
+
* '@makolabs/ripple/funcs/user-management.remote'`) to the strictly-typed
|
|
8
|
+
* `UserManagementAdapter` shape.
|
|
9
|
+
*
|
|
10
|
+
* Why this exists: SvelteKit ≥ 2.56 captures the inner async function's
|
|
11
|
+
* `Promise<X>` as `Output` in `RemoteCommand`'s call signature, so
|
|
12
|
+
* `command('unchecked', async (): Promise<X> => …)` types as
|
|
13
|
+
* `RemoteCommand<I, Promise<X>>` whose call returns `Promise<Promise<X>>`
|
|
14
|
+
* even though at runtime it resolves correctly to `Promise<X>`. That
|
|
15
|
+
* spurious extra wrap makes a direct `import * as adapter from
|
|
16
|
+
* './foo.remote'` reject the `UserManagementAdapter` assignment.
|
|
17
|
+
*
|
|
18
|
+
* The helper performs an `as unknown as` coercion in one place so
|
|
19
|
+
* consumers don't scatter casts in their pages, and so the workaround
|
|
20
|
+
* stays discoverable. Once SvelteKit fixes `RemoteCommand` to use
|
|
21
|
+
* `Awaited<Output>`, this helper becomes a transparent pass-through.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // src/routes/+page.svelte
|
|
26
|
+
* import { adaptUserManagementRemote } from '@makolabs/ripple';
|
|
27
|
+
* import * as remote from './users.remote';
|
|
28
|
+
* const adapter = adaptUserManagementRemote(remote);
|
|
29
|
+
* <UserManagement {adapter} {roles} />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function adaptUserManagementRemote(remote) {
|
|
33
|
+
return remote;
|
|
34
|
+
}
|
|
5
35
|
// Export convenience function to format user display name
|
|
6
36
|
export function getUserDisplayName(user) {
|
|
7
37
|
if (!user)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makolabs/ripple",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Simple Svelte 5 powered component library ✨",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"repository": {
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"
|
|
58
|
-
"
|
|
57
|
+
"@sveltejs/kit": "^2.0.0",
|
|
58
|
+
"svelte": "^5.0.0 || ^6.0.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@eslint/compat": "^1.4.1",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@storybook/addon-svelte-csf": "^5.0.10",
|
|
67
67
|
"@storybook/sveltekit": "^10.0.7",
|
|
68
68
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
69
|
-
"@sveltejs/kit": "^2.
|
|
69
|
+
"@sveltejs/kit": "^2.58.0",
|
|
70
70
|
"@sveltejs/package": "^2.5.4",
|
|
71
71
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
72
72
|
"@tailwindcss/vite": "^4.1.17",
|