lupine.components 1.1.21 → 1.1.23

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 (44) hide show
  1. package/package.json +1 -1
  2. package/src/components/action-sheet-demo.tsx +105 -0
  3. package/src/components/button-demo.tsx +33 -0
  4. package/src/components/button-push-animation-demo.tsx +32 -0
  5. package/src/components/button-push-animation.tsx +8 -4
  6. package/src/components/editable-label-demo.tsx +33 -0
  7. package/src/components/input-with-title-demo.tsx +42 -0
  8. package/src/components/message-box-demo.tsx +107 -0
  9. package/src/components/modal-demo.tsx +56 -0
  10. package/src/components/notice-message-demo.tsx +60 -0
  11. package/src/components/popup-menu-demo.tsx +68 -0
  12. package/src/components/popup-menu.tsx +1 -1
  13. package/src/components/progress-demo.tsx +63 -0
  14. package/src/components/progress.tsx +3 -3
  15. package/src/components/radio-label-demo.tsx +41 -0
  16. package/src/components/redirect-demo.tsx +36 -0
  17. package/src/components/resizable-splitter-demo.tsx +76 -0
  18. package/src/components/resizable-splitter.tsx +6 -6
  19. package/src/components/select-angle-demo.tsx +32 -0
  20. package/src/components/select-with-title-demo.tsx +53 -0
  21. package/src/components/spinner-demo.tsx +52 -0
  22. package/src/components/stars-component-demo.tsx +36 -0
  23. package/src/components/stars-component.tsx +11 -3
  24. package/src/components/switch-option-demo.tsx +36 -0
  25. package/src/components/tabs-demo.tsx +42 -0
  26. package/src/components/text-glow-demo.tsx +46 -0
  27. package/src/components/text-scale-demo.tsx +41 -0
  28. package/src/components/text-wave-demo.tsx +46 -0
  29. package/src/components/toggle-button-demo.tsx +42 -0
  30. package/src/components/toggle-play-button-demo.tsx +56 -0
  31. package/src/components/toggle-switch-demo.tsx +43 -0
  32. package/src/demo/demo-about.tsx +12 -0
  33. package/src/demo/demo-container.tsx +57 -0
  34. package/src/demo/demo-css.tsx +3 -0
  35. package/src/demo/demo-frame-helper.tsx +395 -0
  36. package/src/demo/demo-frame.tsx +139 -0
  37. package/src/demo/demo-index.tsx +17 -0
  38. package/src/demo/demo-page.tsx +198 -0
  39. package/src/demo/demo-registry.ts +54 -0
  40. package/src/demo/demo-render-page.tsx +77 -0
  41. package/src/demo/demo-types.ts +22 -0
  42. package/src/html-editor/buttons_morden.gif +0 -0
  43. package/src/html-editor/h-editor.ts +817 -0
  44. package/src/index.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lupine.components",
3
- "version": "1.1.21",
3
+ "version": "1.1.23",
4
4
  "license": "MIT",
5
5
  "author": "uuware.com",
6
6
  "homepage": "https://github.com/uuware/lupine.js",
@@ -0,0 +1,105 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import {
3
+ ActionSheet,
4
+ ActionSheetSelect,
5
+ ActionSheetMessage,
6
+ ActionSheetInput,
7
+ ActionSheetSelectOptionsProps,
8
+ } from './action-sheet';
9
+ import { Button, ButtonSize } from './button';
10
+
11
+ export const actionSheetDemo: DemoStory<any> = {
12
+ id: 'action-sheet-demo',
13
+ text: 'Action Sheet Demo',
14
+ args: {
15
+ title: 'Select an Action',
16
+ confirmButtonText: 'Confirm Option',
17
+ cancelButtonText: 'Cancel Action',
18
+ },
19
+ argTypes: {
20
+ title: { control: 'text', description: 'Title of the action sheet' },
21
+ confirmButtonText: { control: 'text', description: 'Confirm button text' },
22
+ cancelButtonText: { control: 'text', description: 'Cancel button text' },
23
+ },
24
+ render: (args) => {
25
+ return (
26
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px', padding: '20px' }}>
27
+ <Button
28
+ text='Show Simple Action Sheet'
29
+ size={ButtonSize.Medium}
30
+ onClick={() => {
31
+ ActionSheet.show({
32
+ title: args.title,
33
+ children: <div style={{ padding: '20px' }}>Custom Content Here</div>,
34
+ confirmButtonText: args.confirmButtonText,
35
+ cancelButtonText: args.cancelButtonText,
36
+ handleConfirmClicked: (close) => close('confirm'),
37
+ });
38
+ }}
39
+ />
40
+ <Button
41
+ text='Show Action Sheet Select'
42
+ size={ButtonSize.Medium}
43
+ onClick={() => {
44
+ ActionSheetSelect.show({
45
+ title: args.title,
46
+ options: ['Option A', 'Option B', 'Option C'],
47
+ confirmButtonText: args.confirmButtonText,
48
+ cancelButtonText: args.cancelButtonText,
49
+ handleClicked: (index, close) => {
50
+ console.log('Selected index:', index);
51
+ close('select');
52
+ },
53
+ });
54
+ }}
55
+ />
56
+ <Button
57
+ text='Show Action Sheet Message'
58
+ size={ButtonSize.Medium}
59
+ onClick={() => {
60
+ ActionSheetMessage.show({
61
+ title: args.title,
62
+ message: 'This is a detailed message shown inside the action sheet.',
63
+ confirmButtonText: args.confirmButtonText,
64
+ cancelButtonText: args.cancelButtonText,
65
+ });
66
+ }}
67
+ />
68
+ <Button
69
+ text='Show Action Sheet Input'
70
+ size={ButtonSize.Medium}
71
+ onClick={() => {
72
+ ActionSheetInput.show({
73
+ title: args.title,
74
+ defaultValue: 'Default text',
75
+ confirmButtonText: args.confirmButtonText,
76
+ cancelButtonText: args.cancelButtonText,
77
+ handleConfirmValue: (val, close) => {
78
+ console.log('Input value:', val);
79
+ close('confirm');
80
+ },
81
+ });
82
+ }}
83
+ />
84
+ </div>
85
+ );
86
+ },
87
+ code: `import { ActionSheet, ActionSheetSelect, ActionSheetMessage, ActionSheetInput } from 'lupine.components/components/action-sheet';
88
+
89
+ // Simple Action Sheet
90
+ ActionSheet.show({
91
+ title: 'Select an Action',
92
+ children: <div style={{ padding: '20px' }}>Custom Content Here</div>,
93
+ confirmButtonText: 'Confirm Option',
94
+ cancelButtonText: 'Cancel Action',
95
+ handleConfirmClicked: (close) => close('confirm'),
96
+ });
97
+
98
+ // Action Sheet Select
99
+ ActionSheetSelect.show({
100
+ title: 'Select an Action',
101
+ options: ['Option A', 'Option B', 'Option C'],
102
+ handleClicked: (index, close) => close('select'),
103
+ });
104
+ `,
105
+ };
@@ -0,0 +1,33 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { Button, ButtonProps, ButtonSize } from './button';
3
+
4
+ export const buttonDemo: DemoStory<ButtonProps> = {
5
+ id: 'button-demo',
6
+ text: 'Button Demo',
7
+ args: {
8
+ text: 'Click Me',
9
+ size: ButtonSize.Medium,
10
+ disabled: false,
11
+ },
12
+ argTypes: {
13
+ text: { control: 'text', description: 'The text displayed inside the button' },
14
+ size: {
15
+ control: 'select',
16
+ options: Object.values(ButtonSize),
17
+ description: 'The size of the button',
18
+ },
19
+ disabled: { control: 'boolean', description: 'Whether the button is disabled' },
20
+ },
21
+ render: (args: ButtonProps) => {
22
+ return <Button {...args} />;
23
+ },
24
+ code: `import { Button, ButtonSize } from 'lupine.components/components/button';
25
+
26
+ // Basic Usage
27
+ <Button
28
+ text="Click Me"
29
+ size={ButtonSize.Medium}
30
+ onClick={() => console.log('Clicked!')}
31
+ />
32
+ `,
33
+ };
@@ -0,0 +1,32 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { ButtonPushAnimation, ButtonPushAnimationProps, ButtonPushAnimationSize } from './button-push-animation';
3
+
4
+ export const buttonPushAnimationDemo: DemoStory<ButtonPushAnimationProps> = {
5
+ id: 'button-push-animation-demo',
6
+ text: 'Button Push Animation Demo',
7
+ args: {
8
+ text: 'Push Me',
9
+ size: ButtonPushAnimationSize.Medium,
10
+ disabled: false,
11
+ },
12
+ argTypes: {
13
+ text: { control: 'text', description: 'The text displayed inside the button' },
14
+ size: {
15
+ control: 'select',
16
+ options: Object.values(ButtonPushAnimationSize),
17
+ description: 'The size of the button',
18
+ },
19
+ disabled: { control: 'boolean', description: 'Whether the button is disabled' },
20
+ },
21
+ render: (args: ButtonPushAnimationProps) => {
22
+ return <ButtonPushAnimation {...args} />;
23
+ },
24
+ code: `import { ButtonPushAnimation, ButtonPushAnimationSize } from 'lupine.components/components/button-push-animation';
25
+
26
+ <ButtonPushAnimation
27
+ text="Push Me"
28
+ size={ButtonPushAnimationSize.Medium}
29
+ onClick={() => console.log('Pushed!')}
30
+ />
31
+ `,
32
+ };
@@ -86,6 +86,10 @@ export const ButtonPushAnimation = (props: ButtonPushAnimationProps) => {
86
86
  textShadow: 'rgba(0, 0, 0, 0.1) 0 0 0.1em',
87
87
  userSelect: 'none',
88
88
  },
89
+ '&:disabled .button-inner span': {
90
+ backgroundImage: 'linear-gradient(135deg, rgba(150, 150, 150, 1), rgba(200, 200, 200, 1))',
91
+ opacity: 0.7,
92
+ },
89
93
  '&.button-ss': {
90
94
  borderRadius: '2px',
91
95
  },
@@ -114,17 +118,17 @@ export const ButtonPushAnimation = (props: ButtonPushAnimationProps) => {
114
118
  padding: '0.5rem 1.5rem',
115
119
  fontSize: '2rem',
116
120
  },
117
- '&:active .button-outer': {
121
+ '&:active:not(:disabled) .button-outer': {
118
122
  boxShadow: '0 0 0 0 rgba(5, 5, 5, 1), 0 0 0 0 rgba(5, 5, 5, 0.5), 0 0 0 0 rgba(5, 5, 5, 0.25)',
119
123
  },
120
- '&:active .button-inner': {
124
+ '&:active:not(:disabled) .button-inner': {
121
125
  boxShadow:
122
126
  '0.1em 0.15em 0.05em 0 inset rgba(5, 5, 5, 0.75), -0.025em -0.03em 0.05em 0.025em inset rgba(5, 5, 5, 0.5), 0.25em 0.25em 0.2em 0 inset rgba(5, 5, 5, 0.5), 0 0 0.05em 0.5em inset rgba(255, 255, 255, 0.15), 0 0 0 0 inset rgba(255, 255, 255, 1), 0.12em 0.12em 0.12em inset rgba(255, 255, 255, 0.25), -0.075em -0.12em 0.2em 0.1em inset rgba(5, 5, 5, 0.25)',
123
127
  },
124
- '&:hover .button-inner': {
128
+ '&:hover:not(:disabled) .button-inner': {
125
129
  transform: 'scale(0.99)',
126
130
  },
127
- '&:hover .button-inner span': {
131
+ '&:hover:not(:disabled) .button-inner span': {
128
132
  transform: 'scale(0.975)',
129
133
  },
130
134
  ...props.css,
@@ -0,0 +1,33 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { EditableLabel, EditableLabelProps } from './editable-label';
3
+
4
+ export const editableLabelDemo: DemoStory<EditableLabelProps> = {
5
+ id: 'editable-label-demo',
6
+ text: 'Editable Label Demo',
7
+ args: {
8
+ text: 'Double click to edit me!',
9
+ mandtory: false,
10
+ },
11
+ argTypes: {
12
+ text: { control: 'text', description: 'Initial text content' },
13
+ mandtory: { control: 'boolean', description: 'If true, value cannot be left empty' },
14
+ },
15
+ render: (args: EditableLabelProps) => {
16
+ return (
17
+ <div style={{ padding: '20px', width: '300px' }}>
18
+ <p style={{ color: '#666', fontSize: '13px', marginBottom: '10px' }}>
19
+ Instructions: Double-click the text below to switch to edit mode. Press Enter to save, or Escape to cancel.
20
+ </p>
21
+ <EditableLabel {...args} save={(val) => console.log('Saved:', val)} />
22
+ </div>
23
+ );
24
+ },
25
+ code: `import { EditableLabel } from 'lupine.components/components/editable-label';
26
+
27
+ <EditableLabel
28
+ text="Double click to edit me!"
29
+ mandtory={false}
30
+ save={(val) => console.log('Saved:', val)}
31
+ />
32
+ `,
33
+ };
@@ -0,0 +1,42 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { InputWithTitle } from './input-with-title';
3
+
4
+ export const inputWithTitleDemo: DemoStory<any> = {
5
+ id: 'input-with-title-demo',
6
+ text: 'Input With Title Demo',
7
+ args: {
8
+ title: 'Enter your name',
9
+ defaultValue: 'John Doe',
10
+ width: '250px',
11
+ },
12
+ argTypes: {
13
+ title: { control: 'text', description: 'Title text shown above input' },
14
+ defaultValue: { control: 'text', description: 'Initial default value' },
15
+ width: { control: 'text', description: 'Width of the input container' },
16
+ },
17
+ render: (args) => {
18
+ return (
19
+ <div style={{ padding: '20px' }}>
20
+ {InputWithTitle(
21
+ args.title,
22
+ args.defaultValue,
23
+ (val) => console.log('Input onChange:', val),
24
+ (val) => console.log('Input onInput:', val),
25
+ 'input-base',
26
+ args.width
27
+ )}
28
+ </div>
29
+ );
30
+ },
31
+ code: `import { InputWithTitle } from 'lupine.components/components/input-with-title';
32
+
33
+ {InputWithTitle(
34
+ 'Enter your name', // title
35
+ 'John Doe', // defaultValue
36
+ (val) => console.log('onChange:', val),
37
+ (val) => console.log('onInput:', val),
38
+ 'input-base', // className
39
+ '250px' // width
40
+ )}
41
+ `,
42
+ };
@@ -0,0 +1,107 @@
1
+ import { NotificationColor, NotificationMessage } from 'lupine.components';
2
+ import { DemoStory } from '../demo/demo-types';
3
+ import { MessageBox, MessageBoxButtonProps } from './message-box';
4
+ import { Button, ButtonSize } from './button';
5
+
6
+ export const messageBoxDemo: DemoStory<any> = {
7
+ id: 'message-box-demo',
8
+ text: 'MessageBox Demo',
9
+ args: {
10
+ title: 'System Alert',
11
+ contentMinWidth: '300px',
12
+ },
13
+ argTypes: {
14
+ title: { control: 'text', description: 'Title of the MessageBox' },
15
+ contentMinWidth: { control: 'text', description: 'Minimum width of MessageBox' },
16
+ },
17
+ render: (args) => {
18
+ return (
19
+ <div style={{ padding: '20px' }}>
20
+ <p style={{ color: '#666', marginBottom: '20px' }}>Test different button configurations for MessageBox.</p>
21
+
22
+ <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
23
+ <Button
24
+ text='Yes / No Dialog'
25
+ size={ButtonSize.Medium}
26
+ onClick={() => {
27
+ MessageBox.show({
28
+ title: args.title,
29
+ buttonType: MessageBoxButtonProps.YesNo,
30
+ contentMinWidth: args.contentMinWidth,
31
+ children: <div style={{ padding: '20px' }}>Are you sure you want to proceed?</div>,
32
+ handleClicked: (index, close) => {
33
+ const result = index === 0 ? 'Yes' : 'No';
34
+ NotificationMessage.sendMessage('You clicked: ' + result, NotificationColor.Info);
35
+ close();
36
+ },
37
+ });
38
+ }}
39
+ />
40
+
41
+ <Button
42
+ text='Ok / Cancel Dialog'
43
+ size={ButtonSize.Medium}
44
+ onClick={() => {
45
+ MessageBox.show({
46
+ title: args.title,
47
+ buttonType: MessageBoxButtonProps.OkCancel,
48
+ contentMinWidth: args.contentMinWidth,
49
+ children: <div style={{ padding: '20px' }}>Please confirm this action.</div>,
50
+ handleClicked: (index, close) => {
51
+ const result = index === 0 ? 'OK' : 'Cancel';
52
+ const level = index === 0 ? NotificationColor.Success : NotificationColor.Warning;
53
+ NotificationMessage.sendMessage('You clicked: ' + result, level);
54
+ close();
55
+ },
56
+ });
57
+ }}
58
+ />
59
+
60
+ <Button
61
+ text='Ok Only'
62
+ size={ButtonSize.Medium}
63
+ onClick={() => {
64
+ MessageBox.show({
65
+ title: args.title,
66
+ buttonType: MessageBoxButtonProps.Ok,
67
+ contentMinWidth: args.contentMinWidth,
68
+ children: <div style={{ padding: '20px' }}>Operation completed successfully!</div>,
69
+ handleClicked: (index, close) => {
70
+ NotificationMessage.sendMessage('Dialog dismissed', NotificationColor.Success);
71
+ close();
72
+ },
73
+ });
74
+ }}
75
+ />
76
+ </div>
77
+ </div>
78
+ );
79
+ },
80
+ code: `import { MessageBox, MessageBoxButtonProps } from 'lupine.components/components/message-box';
81
+
82
+ // Quick Alert
83
+ MessageBox.show({
84
+ title: 'System Alert',
85
+ buttonType: MessageBoxButtonProps.Ok,
86
+ children: <div style={{ padding: '20px' }}>Operation completed successfully!</div>,
87
+ handleClicked: (index, close) => {
88
+ close();
89
+ }
90
+ });
91
+
92
+ // Confirmation Dialog
93
+ MessageBox.show({
94
+ title: 'Confirm Action',
95
+ buttonType: MessageBoxButtonProps.OkCancel,
96
+ children: <div style={{ padding: '20px' }}>Are you sure you want to proceed?</div>,
97
+ handleClicked: (index, close) => {
98
+ if (index === 0) {
99
+ console.log('User clicked OK');
100
+ } else {
101
+ console.log('User clicked Cancel');
102
+ }
103
+ close();
104
+ }
105
+ });
106
+ `,
107
+ };
@@ -0,0 +1,56 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { ModalWindow } from './modal';
3
+ import { Button, ButtonSize } from './button';
4
+
5
+ export const modalDemo: DemoStory<any> = {
6
+ id: 'modal-demo',
7
+ text: 'Modal Window Demo',
8
+ args: {
9
+ title: 'Example Modal',
10
+ noMoving: true,
11
+ noModal: false,
12
+ contentMinWidth: '300px',
13
+ },
14
+ argTypes: {
15
+ title: { control: 'text', description: 'Title of the modal' },
16
+ noMoving: { control: 'boolean', description: 'Disable dragging?' },
17
+ noModal: { control: 'boolean', description: "If true, it won't block background interaction" },
18
+ contentMinWidth: { control: 'text', description: 'Minimum width of modal' },
19
+ },
20
+ render: (args) => {
21
+ return (
22
+ <div style={{ padding: '20px' }}>
23
+ <Button
24
+ text='Open Modal'
25
+ size={ButtonSize.Medium}
26
+ onClick={() => {
27
+ ModalWindow.show({
28
+ title: args.title,
29
+ children: <div style={{ padding: '20px' }}>This is the modal content!</div>,
30
+ noMoving: args.noMoving,
31
+ noModal: args.noModal,
32
+ contentMinWidth: args.contentMinWidth,
33
+ buttons: ['Cancel', 'Confirm'],
34
+ handleClicked: (ind, close) => {
35
+ console.log('Clicked button:', ind);
36
+ close();
37
+ },
38
+ });
39
+ }}
40
+ />
41
+ </div>
42
+ );
43
+ },
44
+ code: `import { ModalWindow } from 'lupine.components/components/modal';
45
+
46
+ ModalWindow.show({
47
+ title: 'Example Modal',
48
+ children: <div style={{ padding: '20px' }}>This is the modal content!</div>,
49
+ buttons: ['Cancel', 'Confirm'],
50
+ handleClicked: (ind, close) => {
51
+ console.log('Clicked button:', ind);
52
+ close();
53
+ },
54
+ });
55
+ `,
56
+ };
@@ -0,0 +1,60 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { NotificationMessage, NotificationColor } from './notice-message';
3
+ import { Button, ButtonSize } from './button';
4
+
5
+ export const noticeMessageDemo: DemoStory<any> = {
6
+ id: 'notice-message-demo',
7
+ text: 'Notice Message Demo',
8
+ args: {
9
+ message: 'Action completed successfully!',
10
+ permanent: false,
11
+ showTime: 3000,
12
+ },
13
+ argTypes: {
14
+ message: { control: 'text', description: 'Message content' },
15
+ permanent: { control: 'boolean', description: 'If true, stays until manually closed' },
16
+ showTime: { control: 'number', description: 'Time in ms to show (if not permanent)' },
17
+ },
18
+ render: (args) => {
19
+ return (
20
+ <div style={{ padding: '20px', display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
21
+ <Button
22
+ text='Show Info'
23
+ size={ButtonSize.Medium}
24
+ onClick={() =>
25
+ NotificationMessage.sendMessage(args.message, NotificationColor.Info, args.permanent, args.showTime)
26
+ }
27
+ />
28
+ <Button
29
+ text='Show Success'
30
+ size={ButtonSize.Medium}
31
+ onClick={() =>
32
+ NotificationMessage.sendMessage(args.message, NotificationColor.Success, args.permanent, args.showTime)
33
+ }
34
+ />
35
+ <Button
36
+ text='Show Warning'
37
+ size={ButtonSize.Medium}
38
+ onClick={() =>
39
+ NotificationMessage.sendMessage(args.message, NotificationColor.Warning, args.permanent, args.showTime)
40
+ }
41
+ />
42
+ <Button
43
+ text='Show Error'
44
+ size={ButtonSize.Medium}
45
+ onClick={() =>
46
+ NotificationMessage.sendMessage(args.message, NotificationColor.Error, args.permanent, args.showTime)
47
+ }
48
+ />
49
+ </div>
50
+ );
51
+ },
52
+ code: `import { NotificationMessage, NotificationColor } from 'lupine.components/components/notice-message';
53
+
54
+ // Show Info
55
+ NotificationMessage.sendMessage('Action completed successfully!', NotificationColor.Info);
56
+
57
+ // Show Success (permanent)
58
+ NotificationMessage.sendMessage('Action completed successfully!', NotificationColor.Success, true);
59
+ `,
60
+ };
@@ -0,0 +1,68 @@
1
+ import { DemoStory } from '../demo/demo-types';
2
+ import { PopupMenuWithButton, PopupMenuWithLabel, PopupMenuWithIcon } from './popup-menu';
3
+
4
+ export const popupMenuDemo: DemoStory<any> = {
5
+ id: 'popup-menu-demo',
6
+ text: 'Popup Menu Demo',
7
+ args: {
8
+ label: 'Actions',
9
+ defaultValue: 'Select...',
10
+ align: 'right',
11
+ },
12
+ argTypes: {
13
+ label: { control: 'text', description: 'Label for button/text triggers' },
14
+ defaultValue: { control: 'text', description: 'Default selected text' },
15
+ align: { control: 'select', options: ['left', 'right'], description: 'Menu drop alignment' },
16
+ },
17
+ render: (args) => {
18
+ const list = ['Edit Profile', 'Settings', '', 'Log Out'];
19
+ return (
20
+ <div style={{ padding: '20px', display: 'flex', gap: '40px', alignItems: 'flex-start' }}>
21
+ <div>
22
+ <h3>With Button</h3>
23
+ <PopupMenuWithButton
24
+ label={args.label}
25
+ list={list}
26
+ defaultValue={args.defaultValue}
27
+ align={args.align}
28
+ handleSelected={(val: string) => console.log('Selected:', val)}
29
+ />
30
+ </div>
31
+
32
+ <div>
33
+ <h3>With Label</h3>
34
+ <PopupMenuWithLabel label={args.label} list={list} defaultValue={args.defaultValue} align={args.align} />
35
+ </div>
36
+
37
+ <div>
38
+ <h3>With Icon</h3>
39
+ <PopupMenuWithIcon
40
+ list={list}
41
+ defaultValue={args.defaultValue}
42
+ align={args.align}
43
+ icon={<span style={{ fontSize: '24px' }}>⚙️</span>}
44
+ />
45
+ </div>
46
+ </div>
47
+ );
48
+ },
49
+ code: `import { PopupMenuWithButton, PopupMenuWithLabel, PopupMenuWithIcon } from 'lupine.components/components/popup-menu';
50
+
51
+ const list = ['Edit Profile', 'Settings', '', 'Log Out'];
52
+
53
+ {/* With Button */}
54
+ <PopupMenuWithButton
55
+ label="Actions"
56
+ list={list}
57
+ defaultValue="Select..."
58
+ align="right"
59
+ handleSelected={(val: string) => console.log('Selected:', val)}
60
+ />
61
+
62
+ {/* With Icon */}
63
+ <PopupMenuWithIcon
64
+ list={list}
65
+ icon={<span style={{ fontSize: '24px' }}>⚙️</span>}
66
+ />
67
+ `,
68
+ };
@@ -186,7 +186,7 @@ export const PopupMenu = ({
186
186
  padding: '5px 0px',
187
187
  overflow: 'auto',
188
188
  'line-height': '1.2em',
189
- 'min-width': minWidth || 'auto',
189
+ 'min-width': minWidth || 'max-content',
190
190
  'max-width': maxWidth || '200px',
191
191
  'max-height': maxHeight || '300px',
192
192
  'box-shadow': 'var(--cover-box-shadow)', //'#0000004c 0px 19px 38px, #00000038 0px 15px 12px',
@@ -0,0 +1,63 @@
1
+ import { RefProps } from 'lupine.web';
2
+ import { DemoStory } from '../demo/demo-types';
3
+ import { Progress, ProgressHookProps } from './progress';
4
+
5
+ // Note: Progress uses a singleton-like hook approach internally,
6
+ // so we create a dummy hook object to interact with it.
7
+ const progressHook: ProgressHookProps = {};
8
+
9
+ export const progressDemo: DemoStory<any> = {
10
+ id: 'progress-demo',
11
+ text: 'Progress Demo',
12
+ args: {
13
+ simulate: false,
14
+ },
15
+ argTypes: {
16
+ simulate: {
17
+ control: 'boolean',
18
+ description: 'Check this to simulate a 3-second progress upload',
19
+ },
20
+ },
21
+ render: (args) => {
22
+ const ref: RefProps = {
23
+ onLoad: async () => {
24
+ // If the simulate toggle is flipped, run a fake progression
25
+ if (args.simulate && progressHook.onShow) {
26
+ progressHook.onShow(true, 'Simulating Upload...');
27
+ let p = 0;
28
+ const interval = setInterval(() => {
29
+ p += 3;
30
+ if (p > 100) {
31
+ clearInterval(interval);
32
+ progressHook.onShow!(false);
33
+ } else {
34
+ progressHook.onProgress!(p / 100);
35
+ }
36
+ }, 100);
37
+ } else if (!args.simulate && progressHook.onShow) {
38
+ progressHook.onShow(false);
39
+ }
40
+ },
41
+ };
42
+ return (
43
+ <div ref={ref} style={{ padding: '20px' }}>
44
+ <p style={{ color: '#666' }}>
45
+ Toggle the 'simulate' control to see the fixed progress bar at the bottom of the screen.
46
+ </p>
47
+ <Progress hook={progressHook} />
48
+ </div>
49
+ );
50
+ },
51
+ code: `import { Progress, ProgressHookProps } from 'lupine.components/components/progress';
52
+
53
+ const progressHook: ProgressHookProps = {};
54
+
55
+ // 1. Render the component somewhere in your app (usually near the root)
56
+ <Progress hook={progressHook} />
57
+
58
+ // 2. Control it via the hook
59
+ progressHook.onShow!(true, 'Uploading...'); // Show progress
60
+ progressHook.onProgress!(0.5); // Set to 50%
61
+ progressHook.onShow!(false); // Hide
62
+ `,
63
+ };