1+ import { create , keyframes } from '@stylexjs/stylex' ;
2+
13import { button } from '../dom/button' ;
24import { createElement } from '../utils' ;
35
@@ -23,18 +25,22 @@ const defaultConfig: Partial<ActionButtonConfig> = {
2325 disabled : false ,
2426} ;
2527
26- const styles = {
28+ const styles = create ( {
2729 actionButton : {
28- backgroundColor : '#edf2f7 ' ,
30+ backgroundColor : '#fff ' ,
2931 border : '1px solid #cbd5e0' ,
30- borderRadius : '4px ' ,
31- padding : '3px 8px' ,
32+ borderRadius : '5px ' ,
33+ padding : '5px 8px 3px ' ,
3234 fontSize : '12px' ,
3335 cursor : 'pointer' ,
3436 display : 'flex' ,
3537 alignItems : 'center' ,
36- color : '#4a5568 ' ,
38+ color : '#4B5563 ' ,
3739 opacity : '1' ,
40+ ':disabled' : {
41+ opacity : '0.5' ,
42+ cursor : 'not-allowed' ,
43+ } ,
3844 } ,
3945 icon : {
4046 display : 'inline-block' ,
@@ -45,17 +51,64 @@ const styles = {
4551 backgroundRepeat : 'no-repeat' ,
4652 backgroundPosition : 'center' ,
4753 } ,
48- disabledButton : {
49- opacity : '0.5' ,
50- cursor : 'not-allowed' ,
54+ } ) ;
55+
56+ const icons = create ( {
57+ copy : {
58+ backgroundImage :
59+ "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z'/%3E%3Cpath d='M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z'/%3E%3C/svg%3E\")" ,
60+ } ,
61+ insert : {
62+ backgroundImage :
63+ "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E%3Cpath d='M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z'/%3E%3C/svg%3E\")" ,
5164 } ,
52- } satisfies Record < string , Partial < CSSStyleDeclaration > > ;
65+ } ) ;
5366
54- const icons = {
55- copy : "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z'/%3E%3Cpath d='M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z'/%3E%3C/svg%3E" ,
56- insert :
57- "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E%3Cpath d='M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z'/%3E%3C/svg%3E" ,
58- } ;
67+ const spin = keyframes ( {
68+ from : { transform : 'rotate(0deg)' } ,
69+ to : { transform : 'rotate(360deg)' } ,
70+ } ) ;
71+
72+ const spinnerStyles = create ( {
73+ spinner : {
74+ display : 'inline-block' ,
75+ marginRight : '5px' ,
76+ width : '12px' ,
77+ height : '12px' ,
78+ position : 'relative' ,
79+ animationName : spin ,
80+ animationDuration : '1s' ,
81+ animationTimingFunction : 'linear' ,
82+ animationIterationCount : 'infinite' ,
83+ } ,
84+ dot : {
85+ position : 'absolute' ,
86+ width : '3px' ,
87+ height : '3px' ,
88+ backgroundColor : 'currentColor' ,
89+ borderRadius : '50%' ,
90+ } ,
91+ top : {
92+ top : '0' ,
93+ left : '50%' ,
94+ transform : 'translate(-50%, 0)' ,
95+ } ,
96+ right : {
97+ top : '50%' ,
98+ right : '0' ,
99+ transform : 'translate(0, -50%)' ,
100+ } ,
101+ bottom : {
102+ bottom : '0' ,
103+ left : '50%' ,
104+ transform : 'translate(-50%, 0)' ,
105+ } ,
106+ left : {
107+ top : '50%' ,
108+ left : '0' ,
109+ transform : 'translate(0, -50%)' ,
110+ } ,
111+ } ) ;
59112
60113export const createActionButton = ( config : ActionButtonConfig ) => {
61114 config = {
@@ -68,71 +121,19 @@ export const createActionButton = (config: ActionButtonConfig) => {
68121 const result = config . onClick ( config . message , config . modal ) ;
69122
70123 if ( result instanceof Promise ) {
71- btn . innerHTML = `
72- <span style="
73- display: inline-block;
74- margin-right: 5px;
75- width: 12px;
76- height: 12px;
77- position: relative;
78- animation: spin 1s linear infinite;
79- ">
80- <span style="
81- position: absolute;
82- width: 3px;
83- height: 3px;
84- background-color: currentColor;
85- border-radius: 50%;
86- top: 0;
87- left: 50%;
88- transform: translate(-50%, 0);
89- "></span>
90- <span style="
91- position: absolute;
92- width: 3px;
93- height: 3px;
94- background-color: currentColor;
95- border-radius: 50%;
96- top: 50%;
97- right: 0;
98- transform: translate(0, -50%);
99- "></span>
100- <span style="
101- position: absolute;
102- width: 3px;
103- height: 3px;
104- background-color: currentColor;
105- border-radius: 50%;
106- bottom: 0;
107- left: 50%;
108- transform: translate(-50%, 0);
109- "></span>
110- <span style="
111- position: absolute;
112- width: 3px;
113- height: 3px;
114- background-color: currentColor;
115- border-radius: 50%;
116- top: 50%;
117- left: 0;
118- transform: translate(0, -50%);
119- "></span>
120- </span>
121- ${ config . loadingText }
122- ` ;
123-
124- const style = document . createElement ( 'style' ) ;
125- style . textContent = `
126- @keyframes spin {
127- from { transform: rotate(0deg); }
128- to { transform: rotate(360deg); }
129- }
130- ` ;
131- document . head . appendChild ( style ) ;
124+ const spinner = createElement ( 'span' , spinnerStyles . spinner , [
125+ createElement ( 'span' , [ spinnerStyles . dot , spinnerStyles . top ] ) ,
126+ createElement ( 'span' , [ spinnerStyles . dot , spinnerStyles . right ] ) ,
127+ createElement ( 'span' , [ spinnerStyles . dot , spinnerStyles . bottom ] ) ,
128+ createElement ( 'span' , [ spinnerStyles . dot , spinnerStyles . left ] ) ,
129+ ] ) ;
132130
133- await result ;
131+ btn . innerHTML = createElement ( 'span' , undefined , [
132+ spinner ,
133+ config . loadingText || '' ,
134+ ] ) . outerHTML ;
134135
135- document . head . removeChild ( style ) ;
136+ await result ;
136137 }
137138
138139 btn . innerHTML = `
@@ -144,18 +145,11 @@ export const createActionButton = (config: ActionButtonConfig) => {
144145 } ;
145146
146147 const btn = button (
147- [
148- createElement ( 'span' , {
149- ...styles . icon ,
150- backgroundImage : `url("${ icons [ config . icon ] } ")` ,
151- } ) ,
152- config . label ,
153- ] ,
148+ [ createElement ( 'span' , [ styles . icon , icons [ config . icon ] ] ) , config . label ] ,
154149 onClick ,
155150 styles . actionButton ,
156- styles . disabledButton ,
157151 ) ;
158- btn . className = 'action-button' ;
152+ btn . classList . add ( 'action-button' ) ;
159153
160154 if ( config . disabled ) {
161155 btn . disable ( ) ;
0 commit comments