ywana-core8 0.1.83 → 0.1.85

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 (76) hide show
  1. package/__previewjs__/Wrapper.tsx +8 -5
  2. package/build-doc.sh +10 -0
  3. package/dist/index.cjs +627 -194
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +353 -105
  6. package/dist/index.css.map +1 -1
  7. package/dist/index.modern.js +628 -196
  8. package/dist/index.modern.js.map +1 -1
  9. package/dist/index.umd.js +629 -196
  10. package/dist/index.umd.js.map +1 -1
  11. package/doc/README.md +196 -0
  12. package/doc/craco.config.js +31 -0
  13. package/doc/generate-examples.cjs +310 -0
  14. package/doc/package-lock.json +17298 -0
  15. package/doc/package.json +33 -0
  16. package/doc/public/index.html +22 -0
  17. package/doc/src/App.css +171 -0
  18. package/doc/src/App.js +214 -0
  19. package/doc/src/components/ExamplePage.js +104 -0
  20. package/doc/src/components/WelcomePage.js +84 -0
  21. package/doc/src/examples/button.example.js +47 -0
  22. package/doc/src/examples/input.example.js +91 -0
  23. package/doc/src/index.css +237 -0
  24. package/doc/src/index.js +11 -0
  25. package/package.json +9 -2
  26. package/preview.config.js +38 -0
  27. package/src/html/accordion.example.js +2 -2
  28. package/src/html/actions-cell.css +108 -0
  29. package/src/html/actions-cell.example.js +587 -0
  30. package/src/html/actions-cell.js +260 -0
  31. package/src/html/checkbox.example.js +2 -2
  32. package/src/html/chip.example.js +2 -2
  33. package/src/html/color.example.js +2 -2
  34. package/src/html/form.example.js +2 -2
  35. package/src/html/header2.example.js +2 -2
  36. package/src/html/index.js +1 -0
  37. package/src/html/menu.css +9 -2
  38. package/src/html/menu.js +14 -2
  39. package/src/html/progress.example.js +2 -2
  40. package/src/html/property.example.js +2 -2
  41. package/src/html/radio.example.js +2 -2
  42. package/src/html/switch.example.js +2 -2
  43. package/src/html/tab.example.js +2 -2
  44. package/src/html/table.css +47 -1
  45. package/src/html/table.example.js +1012 -0
  46. package/src/html/table.js +12 -7
  47. package/src/html/table2-actions-test.js +138 -0
  48. package/src/html/table2.css +40 -3
  49. package/src/html/table2.example.js +330 -0
  50. package/src/html/table2.js +56 -13
  51. package/src/html/textfield.css +17 -4
  52. package/src/html/tokenfield.example.js +2 -2
  53. package/src/html/tree.css +42 -7
  54. package/src/html/tree.example.js +169 -7
  55. package/src/html/tree.js +216 -93
  56. package/src/widgets/calendar/Calendar.js +1 -1
  57. /package/{ACCORDION_EVALUATION.md → doc/evalulations/ACCORDION_EVALUATION.md} +0 -0
  58. /package/{CHECKBOX_EVALUATION.md → doc/evalulations/CHECKBOX_EVALUATION.md} +0 -0
  59. /package/{CHIP_EVALUATION.md → doc/evalulations/CHIP_EVALUATION.md} +0 -0
  60. /package/{COLOR_EVALUATION.md → doc/evalulations/COLOR_EVALUATION.md} +0 -0
  61. /package/{COMPONENTS_EVALUATION.md → doc/evalulations/COMPONENTS_EVALUATION.md} +0 -0
  62. /package/{FORM_EVALUATION.md → doc/evalulations/FORM_EVALUATION.md} +0 -0
  63. /package/{HEADER_EVALUATION.md → doc/evalulations/HEADER_EVALUATION.md} +0 -0
  64. /package/{ICON_EVALUATION.md → doc/evalulations/ICON_EVALUATION.md} +0 -0
  65. /package/{LIST_EVALUATION.md → doc/evalulations/LIST_EVALUATION.md} +0 -0
  66. /package/{PROGRESS_EVALUATION.md → doc/evalulations/PROGRESS_EVALUATION.md} +0 -0
  67. /package/{RADIO_EVALUATION.md → doc/evalulations/RADIO_EVALUATION.md} +0 -0
  68. /package/{RADIO_VISUAL_FIX.md → doc/evalulations/RADIO_VISUAL_FIX.md} +0 -0
  69. /package/{SECTION_IMPROVEMENTS.md → doc/evalulations/SECTION_IMPROVEMENTS.md} +0 -0
  70. /package/{SWITCH_EVALUATION.md → doc/evalulations/SWITCH_EVALUATION.md} +0 -0
  71. /package/{SWITCH_VISUAL_FIX.md → doc/evalulations/SWITCH_VISUAL_FIX.md} +0 -0
  72. /package/{TAB_EVALUATION.md → doc/evalulations/TAB_EVALUATION.md} +0 -0
  73. /package/{TEXTFIELD_EVALUATION.md → doc/evalulations/TEXTFIELD_EVALUATION.md} +0 -0
  74. /package/{TOOLTIP_FIX.md → doc/evalulations/TOOLTIP_FIX.md} +0 -0
  75. /package/{TREE_EVALUATION.md → doc/evalulations/TREE_EVALUATION.md} +0 -0
  76. /package/src/incubator/{PDFViewer.js → pdfViewer.js} +0 -0
@@ -0,0 +1,260 @@
1
+ import React, { useState, useRef, useEffect } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { MenuIcon, MenuItem } from './menu'
4
+ import './actions-cell.css'
5
+
6
+ /**
7
+ * ActionsCell - Componente reutilizable para manejar acciones con overflow automático
8
+ *
9
+ * Características:
10
+ * - Detecta automáticamente si las acciones exceden el ancho máximo
11
+ * - Convierte automáticamente a menú desplegable cuando es necesario
12
+ * - Extrae acciones de componentes React para crear elementos de menú
13
+ * - Reutilizable en tablas, headers, accordions, listas, etc.
14
+ */
15
+ export const ActionsCell = ({
16
+ actions,
17
+ maxWidth = 200,
18
+ menuIcon = "more_horiz",
19
+ menuAlign = "left",
20
+ menuSize = "small",
21
+ className = "",
22
+ style = {},
23
+ gap = "4px",
24
+ ...restProps
25
+ }) => {
26
+ const [isOverflowing, setIsOverflowing] = useState(false)
27
+ const [isReady, setIsReady] = useState(false)
28
+ const actionsRef = useRef(null)
29
+ const containerRef = useRef(null)
30
+
31
+ // Check if actions overflow the max width
32
+ useEffect(() => {
33
+ const checkOverflow = () => {
34
+ if (actions) {
35
+ try {
36
+ // Create a temporary element to measure the actual width needed
37
+ const tempDiv = document.createElement('div')
38
+ tempDiv.style.cssText = `
39
+ position: absolute;
40
+ visibility: hidden;
41
+ white-space: nowrap;
42
+ display: flex;
43
+ align-items: center;
44
+ gap: ${gap};
45
+ pointer-events: none;
46
+ z-index: -1000;
47
+ top: -1000px;
48
+ left: -1000px;
49
+ `
50
+
51
+ // Create a wrapper to render the actions
52
+ const actionsWrapper = document.createElement('div')
53
+ actionsWrapper.style.cssText = `
54
+ display: flex;
55
+ align-items: center;
56
+ gap: ${gap};
57
+ flex-wrap: nowrap;
58
+ `
59
+
60
+ // We need to render the React element to measure it properly
61
+ // For now, we'll use a heuristic based on the number of actions
62
+ let estimatedWidth = 0
63
+
64
+ if (actions.props && actions.props.children) {
65
+ const children = Array.isArray(actions.props.children)
66
+ ? actions.props.children
67
+ : [actions.props.children]
68
+
69
+ children.forEach((child) => {
70
+ if (child && child.props) {
71
+ // Estimate width based on button content
72
+ const hasText = child.props.children && typeof child.props.children === 'string'
73
+ const textLength = hasText ? child.props.children.length : 0
74
+
75
+ if (hasText) {
76
+ // Button with text: ~8px per character + 32px for icon + padding
77
+ estimatedWidth += (textLength * 8) + 32 + 16
78
+ } else {
79
+ // Icon-only button: ~32px + padding
80
+ estimatedWidth += 32 + 8
81
+ }
82
+ }
83
+ })
84
+
85
+ // Add gap between buttons
86
+ const gapWidth = parseInt(gap) || 4
87
+ estimatedWidth += (children.length - 1) * gapWidth
88
+ } else {
89
+ // Single action
90
+ const hasText = actions.props && actions.props.children && typeof actions.props.children === 'string'
91
+ const textLength = hasText ? actions.props.children.length : 0
92
+
93
+ if (hasText) {
94
+ estimatedWidth = (textLength * 8) + 32 + 16
95
+ } else {
96
+ estimatedWidth = 32 + 8
97
+ }
98
+ }
99
+
100
+ // Check if it overflows the max width (with some padding for safety)
101
+ const shouldOverflow = estimatedWidth > (maxWidth - 8) // 8px for container padding
102
+ setIsOverflowing(shouldOverflow)
103
+ setIsReady(true)
104
+ } catch (error) {
105
+ console.warn('ActionsCell: Error measuring width', error)
106
+ setIsOverflowing(false)
107
+ setIsReady(true)
108
+ }
109
+ } else {
110
+ setIsReady(true)
111
+ }
112
+ }
113
+
114
+ // Use a small delay to ensure DOM is ready
115
+ const timer = setTimeout(checkOverflow, 10)
116
+ return () => clearTimeout(timer)
117
+ }, [actions, maxWidth, gap])
118
+
119
+ // Extract action items from React elements for menu
120
+ const extractActionItems = (actionsElement) => {
121
+ if (!actionsElement) return []
122
+
123
+ const items = []
124
+
125
+ try {
126
+ // If it's a div with children (multiple actions)
127
+ if (actionsElement.props && actionsElement.props.children) {
128
+ const children = Array.isArray(actionsElement.props.children)
129
+ ? actionsElement.props.children
130
+ : [actionsElement.props.children]
131
+
132
+ children.forEach((child, index) => {
133
+ if (child && child.props) {
134
+ const { icon, children: label, onClick, disabled, title } = child.props
135
+ items.push({
136
+ id: `action-${index}`,
137
+ icon: icon,
138
+ label: title || label || `Action ${index + 1}`,
139
+ onSelect: onClick,
140
+ disabled: disabled
141
+ })
142
+ }
143
+ })
144
+ } else if (actionsElement.props) {
145
+ // Single action
146
+ const { icon, children: label, onClick, disabled, title } = actionsElement.props
147
+ items.push({
148
+ id: 'action-0',
149
+ icon: icon,
150
+ label: title || label || 'Action',
151
+ onSelect: onClick,
152
+ disabled: disabled
153
+ })
154
+ }
155
+ } catch (error) {
156
+ console.warn('ActionsCell: Error extracting action items', error)
157
+ }
158
+
159
+ return items
160
+ }
161
+
162
+ if (!actions) return null
163
+
164
+ const containerClasses = [
165
+ 'actions-cell',
166
+ className
167
+ ].filter(Boolean).join(' ')
168
+
169
+ const containerStyles = {
170
+ maxWidth: `${maxWidth}px`,
171
+ width: isOverflowing ? 'auto' : 'fit-content',
172
+ ...style
173
+ }
174
+
175
+ return (
176
+ <div
177
+ ref={containerRef}
178
+ className={containerClasses}
179
+ style={containerStyles}
180
+ {...restProps}
181
+ >
182
+ {!isReady ? (
183
+ // Loading state - show a minimal placeholder
184
+ <div className="actions-cell__loading" style={{ width: '48px', height: '32px' }} />
185
+ ) : !isOverflowing ? (
186
+ // Show actions normally
187
+ <div
188
+ ref={actionsRef}
189
+ className="actions-cell__content"
190
+ style={{
191
+ display: 'flex',
192
+ alignItems: 'center',
193
+ gap: gap,
194
+ flexWrap: 'nowrap'
195
+ }}
196
+ >
197
+ {actions}
198
+ </div>
199
+ ) : (
200
+ // Show menu when overflowing
201
+ <>
202
+ {/* Hidden div for measurement */}
203
+ <div
204
+ ref={actionsRef}
205
+ style={{
206
+ position: 'absolute',
207
+ visibility: 'hidden',
208
+ whiteSpace: 'nowrap',
209
+ display: 'flex',
210
+ alignItems: 'center',
211
+ gap: gap,
212
+ pointerEvents: 'none',
213
+ zIndex: -1000
214
+ }}
215
+ >
216
+ {actions}
217
+ </div>
218
+
219
+ {/* Menu icon */}
220
+ <MenuIcon
221
+ icon={menuIcon}
222
+ size={menuSize}
223
+ align={menuAlign}
224
+ >
225
+ {extractActionItems(actions).map((item) => (
226
+ <MenuItem
227
+ key={item.id}
228
+ icon={item.icon}
229
+ label={item.label}
230
+ onSelect={item.onSelect}
231
+ disabled={item.disabled}
232
+ />
233
+ ))}
234
+ </MenuIcon>
235
+ </>
236
+ )}
237
+ </div>
238
+ )
239
+ }
240
+
241
+ ActionsCell.propTypes = {
242
+ /** Acciones a mostrar (componentes React) */
243
+ actions: PropTypes.node,
244
+ /** Ancho máximo antes de convertirse en menú */
245
+ maxWidth: PropTypes.number,
246
+ /** Icono del menú desplegable */
247
+ menuIcon: PropTypes.string,
248
+ /** Alineación del menú (left: se abre hacia la izquierda, right: hacia la derecha, center: centrado) */
249
+ menuAlign: PropTypes.oneOf(['left', 'right', 'center']),
250
+ /** Tamaño del icono del menú */
251
+ menuSize: PropTypes.oneOf(['small', 'medium', 'large']),
252
+ /** Clase CSS adicional */
253
+ className: PropTypes.string,
254
+ /** Estilos adicionales */
255
+ style: PropTypes.object,
256
+ /** Espacio entre acciones */
257
+ gap: PropTypes.string
258
+ }
259
+
260
+ export default ActionsCell
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { CheckBox } from '
3
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./checkbox'
2
+ import { CheckBox } from './checkbox'
3
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
4
4
 
5
5
  /**
6
6
  * Ejemplos de uso del componente CheckBox mejorado
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { Chip, Chips } from '
3
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./chip'
2
+ import { Chip, Chips } from './chip'
3
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
4
4
 
5
5
  /**
6
6
  * Ejemplos de uso de los componentes Chip mejorados
@@ -1,8 +1,8 @@
1
1
  import React, { useState } from 'react'
2
2
  import { ColorField, ColorPicker, ColorUtils } from './color'
3
3
  import { Button } from './button'
4
- import { Text } from '
5
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./text'
4
+ import { Text } from './text'
5
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
6
6
 
7
7
  /**
8
8
  * Ejemplos del componente Color mejorado manteniendo 100% compatibilidad
@@ -3,8 +3,8 @@ import { Form } from './form'
3
3
  import { TextField2 } from './textfield2'
4
4
  import { Button } from './button'
5
5
  import { RadioGroup } from './radio'
6
- import { Chips } from '
7
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./chip'
6
+ import { Chips } from './chip'
7
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
8
8
 
9
9
  /**
10
10
  * Ejemplos de uso del componente Form mejorado
@@ -1,8 +1,8 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Header2 } from './header2'
3
3
  import { Button } from './button'
4
- import { Icon } from '
5
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./icon'
4
+ import { Icon } from './icon'
5
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
6
6
 
7
7
  /**
8
8
  * Ejemplos de uso del componente Header2 mejorado
package/src/html/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { Accordion } from './accordion'
2
+ export { ActionsCell } from './actions-cell'
2
3
  export { Button, ActionButton } from './button'
3
4
  export { CheckBox } from './checkbox'
4
5
  export { Chips, Chip } from './chip'
package/src/html/menu.css CHANGED
@@ -2,18 +2,20 @@
2
2
  position: relative;
3
3
  }
4
4
 
5
+ /* Solución simple: z-index muy alto para que aparezca por encima de todo */
6
+
5
7
  .menu-icon > .overlay {
6
8
  position: fixed;
7
9
  top: 0px;
8
10
  left: 0px;
9
11
  width: 100vw;
10
12
  height: 100vh;
11
- z-index: 5;
13
+ z-index: 9998;
12
14
  background-color: transparent;
13
15
  }
14
16
 
15
17
  .menu-icon > menu {
16
- z-index: 6;
18
+ z-index: 9999;
17
19
  position: absolute;
18
20
  top: 3rem;
19
21
  left: 0px;
@@ -33,6 +35,11 @@
33
35
  right: 0px;
34
36
  }
35
37
 
38
+ .menu-icon > menu.alignLeft {
39
+ left: 0px;
40
+ right: unset;
41
+ }
42
+
36
43
  .menu-icon > menu ul {
37
44
  list-style: none;
38
45
  margin: 0;
package/src/html/menu.js CHANGED
@@ -27,19 +27,31 @@ export const Menu = (props) => {
27
27
  */
28
28
  export const MenuIcon = (props) => {
29
29
 
30
- const { icon = "more_vert", children, align, size="normal" } = props
30
+ const { icon = "more_vert", children, align = "left", size="normal" } = props
31
31
  const [open, setOpen] = useState(false)
32
32
 
33
33
  function toggle() {
34
34
  setOpen(!open)
35
35
  }
36
36
 
37
+ // Convertir valores de align a clases CSS
38
+ const getAlignClass = (alignment) => {
39
+ switch (alignment) {
40
+ case 'right':
41
+ return 'alignRight'
42
+ case 'left':
43
+ return 'alignLeft'
44
+ default:
45
+ return 'alignLeft' // Por defecto a la izquierda
46
+ }
47
+ }
48
+
37
49
  return (
38
50
  <MenuContext.Provider value={[open, setOpen]}>
39
51
  <div className="menu-icon">
40
52
  <Icon icon={icon} size={size} clickable action={toggle} />
41
53
  {open ? (
42
- <menu className={`${align}`}>
54
+ <menu className={getAlignClass(align)}>
43
55
  {children}
44
56
  </menu>
45
57
  ) : null}
@@ -1,8 +1,8 @@
1
1
  import React, { useState, useEffect } from 'react'
2
2
  import { CircularProgress, LinearProgress, StepProgress, RadialProgress, MultiProgress } from './progress'
3
3
  import { Button } from './button'
4
- import { Icon } from '
5
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./icon'
4
+ import { Icon } from './icon'
5
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
6
6
 
7
7
  /**
8
8
  * Ejemplos espectaculares de los componentes Progress mejorados
@@ -1,8 +1,8 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Property } from './property'
3
3
  import { Button } from './button'
4
- import { Text } from '
5
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./text'
4
+ import { Text } from './text'
5
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
6
6
 
7
7
  /**
8
8
  * Ejemplos del componente Property mejorado manteniendo 100% compatibilidad
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { RadioButton, RadioGroup } from '
3
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./radio'
2
+ import { RadioButton, RadioGroup } from './radio'
3
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
4
4
 
5
5
  /**
6
6
  * Ejemplos de uso de los componentes Radio mejorados
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { Switch, Switch2 } from '
3
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./switch'
2
+ import { Switch, Switch2 } from './switch'
3
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
4
4
 
5
5
  /**
6
6
  * Ejemplos de uso de los componentes Switch mejorados
@@ -1,8 +1,8 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Tabs, Tab, Stack } from './tab'
3
3
  import { Button } from './button'
4
- import { Icon } from '
5
- import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'./icon'
4
+ import { Icon } from './icon'
5
+ import { ExampleLayout, ExampleSection, ExampleSubsection, CodeSnippet } from './ExampleLayout'
6
6
 
7
7
  /**
8
8
  * Ejemplos de los componentes Tab mejorados manteniendo 100% compatibilidad
@@ -12,6 +12,7 @@
12
12
 
13
13
  .datatable8 table {
14
14
  width: 100%;
15
+ table-layout: auto;
15
16
  }
16
17
 
17
18
  .datatable8 thead {
@@ -66,7 +67,26 @@
66
67
  white-space: nowrap;
67
68
  max-width: 10rem;
68
69
  color: var(--text-color-light);
69
- }
70
+ }
71
+
72
+ /* Columna de acciones - ajuste automático al contenido */
73
+ .datatable8 tbody td.actions {
74
+ max-width: none !important;
75
+ width: auto;
76
+ min-width: auto;
77
+ white-space: nowrap;
78
+ padding: 0 0.25rem;
79
+ text-align: right;
80
+ overflow: visible;
81
+ text-overflow: unset;
82
+ }
83
+
84
+ /* Header de columna de acciones */
85
+ .datatable8 thead th.actions {
86
+ width: auto;
87
+ min-width: auto;
88
+ padding: 0 0.25rem;
89
+ }
70
90
 
71
91
  .datatable8 tbody td.index {
72
92
  width: 3rem;
@@ -84,6 +104,16 @@
84
104
  border-color: var(--text-color-lighter) !important;
85
105
  }
86
106
 
107
+ .datatable8 tbody td.actions>div {
108
+ display: flex;
109
+ flex-direction: row;
110
+ align-items: center;
111
+ justify-content: flex-end;
112
+ gap: 0.25rem;
113
+ overflow: visible;
114
+ min-width: max-content;
115
+ }
116
+
87
117
  .datatable8 .string-viewer img {
88
118
  height: 5rem;
89
119
  }
@@ -91,4 +121,20 @@
91
121
  .datatable8 th.resizable-column {
92
122
  resize: horizontal;
93
123
  overflow: hidden;
124
+ }
125
+
126
+ /* Columna de info - ancho mínimo para el icono de expansión */
127
+ .datatable8 thead th[style*="width: 3rem"] {
128
+ width: 3rem !important;
129
+ min-width: 3rem;
130
+ max-width: 3rem;
131
+ padding: 0 0.5rem;
132
+ }
133
+
134
+ .datatable8 tbody td:last-child {
135
+ width: 3rem;
136
+ min-width: 3rem;
137
+ max-width: 3rem;
138
+ padding: 0 0.5rem;
139
+ text-align: center;
94
140
  }