nitro-web 0.0.40 → 0.0.41

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.
@@ -11,8 +11,6 @@ import {
11
11
  EyeSlashIcon,
12
12
  } from '@heroicons/react/20/solid'
13
13
  // Maybe use fill-current tw class for lucide icons (https://github.com/lucide-icons/lucide/discussions/458)
14
- import FieldTime, { FieldTimeProps } from './field-time'
15
- import ClockIcon from '../icons/clock'
16
14
 
17
15
  type InputProps = React.InputHTMLAttributes<HTMLInputElement>
18
16
  type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
@@ -22,7 +20,7 @@ type FieldExtraProps = {
22
20
  id?: string
23
21
  // state object to get the value, and check errors against
24
22
  state?: { errors?: Errors, [key: string]: unknown }
25
- type?: 'text' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'time' | 'color'
23
+ type?: 'text' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'color'
26
24
  icon?: React.ReactNode
27
25
  iconPos?: 'left' | 'right'
28
26
  }
@@ -38,7 +36,6 @@ export type FieldProps = (
38
36
  | ({ type: 'currency' } & FieldCurrencyProps & FieldExtraProps)
39
37
  | ({ type: 'color' } & FieldColorProps & FieldExtraProps)
40
38
  | ({ type: 'date' } & FieldDateProps & FieldExtraProps)
41
- | ({ type: 'time' } & FieldTimeProps & FieldExtraProps)
42
39
  )
43
40
 
44
41
  export function Field({ state, icon, iconPos: ip, ...props }: FieldProps) {
@@ -89,8 +86,6 @@ export function Field({ state, icon, iconPos: ip, ...props }: FieldProps) {
89
86
  Icon = <IconWrapper iconPos={iconPos} icon={icon || <ColorSvg hex={value}/>} className="size-[17px]" />
90
87
  } else if (type == 'date') {
91
88
  Icon = <IconWrapper iconPos={iconPos} icon={icon || <CalendarIcon />} className="size-4" />
92
- } else if (type == 'time') {
93
- Icon = <IconWrapper iconPos={iconPos} icon={icon || <ClockIcon />} className="size-4" />
94
89
  } else {
95
90
  Icon = <IconWrapper iconPos={iconPos} icon={icon} />
96
91
  }
@@ -130,12 +125,6 @@ export function Field({ state, icon, iconPos: ip, ...props }: FieldProps) {
130
125
  <FieldDate {...props} {...commonProps} Icon={Icon} />
131
126
  </FieldContainer>
132
127
  )
133
- } else if (type == 'time') {
134
- return (
135
- <FieldContainer error={error} className={props.className}>
136
- <FieldTime {...props} {...commonProps} Icon={Icon} />
137
- </FieldContainer>
138
- )
139
128
  }
140
129
  }
141
130
 
@@ -14,7 +14,6 @@ export function Styleguide() {
14
14
  date: Date.now(),
15
15
  'date-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 33],
16
16
  'date-time': Date.now(),
17
- time: '0',
18
17
  calendar: [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 8],
19
18
  firstName: 'Bruce',
20
19
  errors: [
@@ -40,30 +39,13 @@ export function Styleguide() {
40
39
  ]
41
40
 
42
41
  function onInputChange (e: { target: { id: string, value: unknown } }) {
43
- const {id} = e.target
44
- let {value} = e.target
45
- if ((id == 'customer' || id == 'customer2') && value == '') {
42
+ if ((e.target.id == 'customer' || e.target.id == 'customer2') && e.target.value == '') {
46
43
  setCustomerSearch('')
47
- value = null // clear the selected value
44
+ e.target.value = null // clear the selected value
48
45
  }
49
- const newValue = value
50
- console.dir('newValue')
51
- console.dir(newValue)
52
- setState(s => ({ ...s, [id]: newValue }))
46
+ setState(s => ({ ...s, [e.target.id]: e.target.value }))
53
47
  }
54
48
 
55
- /**
56
- * handleTimeChange
57
- */
58
- const handleTimeChange = () => ({ id, value }: { id: string, value: number | number[] }) => {
59
- if (Array.isArray(value)) return
60
-
61
- setState((state) => ({
62
- ...state,
63
- [id]: value,
64
- }))
65
- }
66
-
67
49
  function onCustomerSearch (search: string) {
68
50
  setCustomerSearch(search || '')
69
51
  }
@@ -287,10 +269,6 @@ export function Styleguide() {
287
269
  <label for="date">Date (right aligned)</label>
288
270
  <Field name="date" type="date" state={state} onChange={onInputChange} dir="bottom-right" />
289
271
  </div>
290
- <div>
291
- <label for="time">Time</label>
292
- <Field name="time" type="time" state={state} value={state.time} onChange={handleTimeChange} />
293
- </div>
294
272
  </div>
295
273
 
296
274
  <h2 class="h3">File Inputs & Calendar</h2>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.40",
3
+ "version": "0.0.41",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
@@ -1,163 +0,0 @@
1
- import React, { useState, useMemo, useCallback, JSX, useEffect } from 'react'
2
- import { css, theme } from 'twin.macro'
3
- import { Dropdown } from 'nitro-web'
4
- import ClockIcon from '../icons/clock'
5
-
6
- export interface FieldTimeProps {
7
- className?: string;
8
- placeholder?: string;
9
- id?: string;
10
- onChange: (values: { id: string; value: number; isFalse: boolean }) => void;
11
- value: string;
12
- isFull?: boolean;
13
- Icon?: JSX.Element;
14
- required?: boolean;
15
- onFalseCondition?: (id: string, time: number) => boolean
16
- }
17
-
18
- export function FieldTime({
19
- className, placeholder = '', id = '', onChange, value, isFull = true, Icon = <ClockIcon />, required = false, onFalseCondition, ...rest
20
- }: FieldTimeProps) {
21
-
22
- // Parse the incoming time value
23
- const [time, setTime] = useState(() => Number(value) || 0)
24
-
25
- const handleTimeChange = useCallback((isHour: boolean, e: React.ChangeEvent<HTMLSelectElement>) => {
26
- const timeStr = e.target.value
27
- const number = parseInt(timeStr)
28
- const hours = Math.floor(time / (60 * 60 * 1000))
29
- const minutes = Math.floor((time % (60 * 60 * 1000)) / (60 * 1000))
30
- const newTime = isHour ? (number * 60 * 60 * 1000) + (minutes * 60 * 1000) : (hours * 60 * 60 * 1000) + (number * 60 * 1000)
31
-
32
- const isFalse = onFalseCondition ? onFalseCondition(id, newTime) : false // if false, not update
33
-
34
- if (!isFalse) setTime(newTime)
35
-
36
- if (onChange) onChange({ id: id, value: newTime, isFalse: isFalse })
37
-
38
- }, [time, id, onChange, onFalseCondition])
39
-
40
- const hoursTime = useMemo(() => Math.floor(time / (60 * 60 * 1000)), [time])
41
-
42
- const minutesTime = useMemo(() => Math.floor((time % (60 * 60 * 1000)) / (60 * 1000)), [time])
43
-
44
- const [displayTime, setDisplayTime] = useState('00:00')
45
-
46
- const secondOptions = useMemo(() => {
47
- const [_hours, minutes] = displayTime.split(':').map(Number)
48
- return [...new Set([minutes, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55])]
49
- }, [displayTime])
50
-
51
- useEffect(() => {
52
- setDisplayTime(`${String(hoursTime).padStart(2, '0')}:${String(minutesTime).padStart(2, '0')}`)
53
- }, [hoursTime, minutesTime])
54
-
55
- return (
56
- <Dropdown
57
- className={isFull ? 'w-full' : 'w-auto'}
58
- // @ts-ignore
59
- css={style}
60
- menuToggles={false}
61
- animate={false}
62
- menuChildren={
63
- <div className="time-picker-container">
64
- <div className="time-picker-selectors">
65
- <select
66
- className="time-select"
67
- value={hoursTime}
68
- onChange={(e) => handleTimeChange(true, e)}
69
- >
70
- {[...Array(24).keys()].map(i => (
71
- <option key={i} value={i}>{String(i).padStart(2, '0')}</option>
72
- ))}
73
- </select>
74
- <span className="time-separator">:</span>
75
- <select
76
- className="time-select"
77
- value={minutesTime}
78
- onChange={(e) => handleTimeChange(false, e)}
79
- >
80
- {secondOptions.map(option => (
81
- <option key={option} value={option}>{String(option).padStart(2, '0')}</option>
82
- ))}
83
- </select>
84
- </div>
85
- </div>
86
- }
87
- >
88
- <div className="grid grid-cols-1">
89
- {Icon}
90
- <input
91
- {...rest}
92
- key={id}
93
- id={id}
94
- autoComplete="off"
95
- className={`hide-time-icon font-medium text-sm placeholder-font-medium placeholder-sm ${className}`}
96
- value={displayTime}
97
- onChange={(e) => {
98
- const newStr = e.target.value
99
- const isValid = /^[0-9]{2}:[0-9]{2}$/.test(newStr)
100
- if (!isValid) {
101
- setDisplayTime(newStr)
102
- return
103
- }
104
- const [hours, minutes] = newStr.split(':').map(Number)
105
- const newNum = (hours * 60 + minutes) * 60 * 1000
106
-
107
- setTime(newNum)
108
- setDisplayTime(newStr)
109
- }}
110
- placeholder={placeholder}
111
- required={required}
112
- />
113
- </div>
114
- </Dropdown>
115
- )
116
- }
117
-
118
- export default FieldTime
119
-
120
- const style = css`
121
- .time-picker-container {
122
- padding: 15px;
123
- font-size: 14px;
124
- background-color: white;
125
- border-radius: 8px;
126
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
127
- }
128
-
129
- .time-picker-selectors {
130
- display: flex;
131
- justify-content: center;
132
- align-items: center;
133
- gap: 5px;
134
- }
135
-
136
- .time-separator {
137
- font-size: 18px;
138
- font-weight: bold;
139
- }
140
-
141
- .time-select {
142
- width: 60px;
143
- padding: 8px;
144
- font-size: 14px;
145
- border: 1px solid #ccc;
146
- border-radius: 4px;
147
- }
148
-
149
- .time-confirm-btn {
150
- padding: 8px 16px;
151
- font-size: 16px;
152
- background-color: ${theme`colors.primary`};
153
- color: white;
154
- border: none;
155
- border-radius: 4px;
156
- cursor: pointer;
157
- margin-top: 10px;
158
- }
159
-
160
- .time-confirm-btn:hover {
161
- background-color: ${theme`colors.primary`};
162
- }
163
- `
@@ -1,18 +0,0 @@
1
- import { theme } from 'twin.macro'
2
-
3
- const ClockIcon = () => {
4
- return (
5
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
6
- <g opacity="0.5" clipPath="url(#clip0_12681_10783)">
7
- <path d="M8.00016 3.99998V7.99998L10.6668 9.33331M14.6668 7.99998C14.6668 11.6819 11.6821 14.6666 8.00016 14.6666C4.31826 14.6666 1.3335 11.6819 1.3335 7.99998C1.3335 4.31808 4.31826 1.33331 8.00016 1.33331C11.6821 1.33331 14.6668 4.31808 14.6668 7.99998Z" stroke={theme`colors.input`} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
8
- </g>
9
- <defs>
10
- <clipPath id="clip0_12681_10783">
11
- <rect width="16" height="16" fill="white" />
12
- </clipPath>
13
- </defs>
14
- </svg>
15
- )
16
- }
17
-
18
- export default ClockIcon