@stoker-platform/web-app 0.5.64 → 0.5.65

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @stoker-platform/web-app
2
2
 
3
+ ## 0.5.65
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: improve modal overscroll behaviour
8
+
3
9
  ## 0.5.64
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoker-platform/web-app",
3
- "version": "0.5.64",
3
+ "version": "0.5.65",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "scripts": {
@@ -2229,59 +2229,63 @@ function Collection({
2229
2229
  >
2230
2230
  <div className="fixed inset-0 bg-black/50" />
2231
2231
  <div
2232
- className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[90vh] overflow-y-auto border border-border"
2232
+ className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[90vh] overflow-hidden border border-border"
2233
2233
  aria-labelledby="dialog-title"
2234
2234
  >
2235
- <div className="space-y-2">
2236
- <div className="flex justify-between items-center mb-4">
2237
- <h4
2238
- id="dialog-title"
2239
- className="font-medium leading-none"
2240
- >
2241
- Add {recordTitle}
2242
- </h4>
2243
- <Button
2244
- type="button"
2245
- variant="ghost"
2246
- size="icon"
2247
- className="right-4 top-4"
2248
- onClick={() => {
2235
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
2236
+ <div className="space-y-2">
2237
+ <div className="flex justify-between items-center mb-4">
2238
+ <h4
2239
+ id="dialog-title"
2240
+ className="font-medium leading-none"
2241
+ >
2242
+ Add {recordTitle}
2243
+ </h4>
2244
+ <Button
2245
+ type="button"
2246
+ variant="ghost"
2247
+ size="icon"
2248
+ className="right-4 top-4"
2249
+ onClick={() => {
2250
+ setIsCreateDialogOpen(false)
2251
+ setSelectedDateRange(null)
2252
+ setTimeout(() => {
2253
+ addButtonRef.current?.focus()
2254
+ }, 0)
2255
+
2256
+ localStorage.removeItem(
2257
+ `stoker-draft-${labels.collection}`,
2258
+ )
2259
+ }}
2260
+ >
2261
+ <X className="h-4 w-4" />
2262
+ <span className="sr-only">Close</span>
2263
+ </Button>
2264
+ </div>
2265
+ <RecordForm
2266
+ collection={collection}
2267
+ operation="create"
2268
+ path={[labels.collection]}
2269
+ record={createPrePopulatedRecord()}
2270
+ draft={true}
2271
+ parentCollection={
2272
+ relationCollection?.labels.collection
2273
+ }
2274
+ parentRecord={relationParent}
2275
+ onSuccess={() => {
2249
2276
  setIsCreateDialogOpen(false)
2250
2277
  setSelectedDateRange(null)
2251
2278
  setTimeout(() => {
2252
2279
  addButtonRef.current?.focus()
2253
2280
  }, 0)
2254
-
2255
- localStorage.removeItem(
2256
- `stoker-draft-${labels.collection}`,
2257
- )
2281
+ if (isServerReadOnly) {
2282
+ setBackToStartKey(
2283
+ (prev) => prev + 1,
2284
+ )
2285
+ }
2258
2286
  }}
2259
- >
2260
- <X className="h-4 w-4" />
2261
- <span className="sr-only">Close</span>
2262
- </Button>
2287
+ />
2263
2288
  </div>
2264
- <RecordForm
2265
- collection={collection}
2266
- operation="create"
2267
- path={[labels.collection]}
2268
- record={createPrePopulatedRecord()}
2269
- draft={true}
2270
- parentCollection={
2271
- relationCollection?.labels.collection
2272
- }
2273
- parentRecord={relationParent}
2274
- onSuccess={() => {
2275
- setIsCreateDialogOpen(false)
2276
- setSelectedDateRange(null)
2277
- setTimeout(() => {
2278
- addButtonRef.current?.focus()
2279
- }, 0)
2280
- if (isServerReadOnly) {
2281
- setBackToStartKey((prev) => prev + 1)
2282
- }
2283
- }}
2284
- />
2285
2289
  </div>
2286
2290
  </div>
2287
2291
  </div>,
@@ -2299,72 +2303,76 @@ function Collection({
2299
2303
  role="dialog"
2300
2304
  >
2301
2305
  <div className="fixed inset-0 bg-black/50" />
2302
- <div className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[50vh] overflow-y-auto border border-border">
2303
- <div className="flex items-center justify-between mb-4">
2304
- <h4 className="font-medium leading-none">
2305
- Select {recordTitle}
2306
- </h4>
2307
- <Button
2308
- type="button"
2309
- variant="ghost"
2310
- size="icon"
2311
- onClick={() => {
2312
- setShowSelectExisting(false)
2313
- setSelectableSearch("")
2314
- setSelectableData([])
2315
- }}
2316
- >
2317
- <X className="h-4 w-4" />
2318
- <span className="sr-only">Close</span>
2319
- </Button>
2320
- </div>
2321
- <div>
2322
- <Command filter={() => 1}>
2323
- <CommandInput
2324
- placeholder={`Search ${collectionTitle}...`}
2325
- className="h-9"
2326
- value={selectableSearch}
2327
- onValueChange={(value) => {
2328
- setSelectableSearch(value)
2329
- fetchSelectableRecords(value)
2306
+ <div className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[50vh] overflow-hidden border border-border">
2307
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
2308
+ <div className="flex items-center justify-between mb-4">
2309
+ <h4 className="font-medium leading-none">
2310
+ Select {recordTitle}
2311
+ </h4>
2312
+ <Button
2313
+ type="button"
2314
+ variant="ghost"
2315
+ size="icon"
2316
+ onClick={() => {
2317
+ setShowSelectExisting(false)
2318
+ setSelectableSearch("")
2319
+ setSelectableData([])
2330
2320
  }}
2331
- />
2332
- <CommandList className="max-h-full sm:max-h-[calc(50vh-138px)]">
2333
- <CommandEmpty>
2334
- {selectLoading ? (
2335
- <LoadingSpinner
2336
- size={7}
2337
- className="m-auto"
2338
- />
2339
- ) : !selectLoadingImmediate ? (
2340
- `No ${collectionTitle} found.`
2341
- ) : null}
2342
- </CommandEmpty>
2343
- {(!selectLoading ||
2344
- isPreloadCacheEnabled) && (
2345
- <CommandGroup>
2346
- {selectableData.map((record) => (
2347
- <CommandItem
2348
- key={record.id}
2349
- value={record.id}
2350
- onSelect={() => {
2351
- linkExistingRecord(
2352
- record,
2353
- )
2354
- }}
2355
- >
2356
- {
2357
- record[
2358
- recordTitleField ||
2359
- "id"
2360
- ]
2361
- }
2362
- </CommandItem>
2363
- ))}
2364
- </CommandGroup>
2365
- )}
2366
- </CommandList>
2367
- </Command>
2321
+ >
2322
+ <X className="h-4 w-4" />
2323
+ <span className="sr-only">Close</span>
2324
+ </Button>
2325
+ </div>
2326
+ <div>
2327
+ <Command filter={() => 1}>
2328
+ <CommandInput
2329
+ placeholder={`Search ${collectionTitle}...`}
2330
+ className="h-9"
2331
+ value={selectableSearch}
2332
+ onValueChange={(value) => {
2333
+ setSelectableSearch(value)
2334
+ fetchSelectableRecords(value)
2335
+ }}
2336
+ />
2337
+ <CommandList className="max-h-full sm:max-h-[calc(50vh-138px)]">
2338
+ <CommandEmpty>
2339
+ {selectLoading ? (
2340
+ <LoadingSpinner
2341
+ size={7}
2342
+ className="m-auto"
2343
+ />
2344
+ ) : !selectLoadingImmediate ? (
2345
+ `No ${collectionTitle} found.`
2346
+ ) : null}
2347
+ </CommandEmpty>
2348
+ {(!selectLoading ||
2349
+ isPreloadCacheEnabled) && (
2350
+ <CommandGroup>
2351
+ {selectableData.map(
2352
+ (record) => (
2353
+ <CommandItem
2354
+ key={record.id}
2355
+ value={record.id}
2356
+ onSelect={() => {
2357
+ linkExistingRecord(
2358
+ record,
2359
+ )
2360
+ }}
2361
+ >
2362
+ {
2363
+ record[
2364
+ recordTitleField ||
2365
+ "id"
2366
+ ]
2367
+ }
2368
+ </CommandItem>
2369
+ ),
2370
+ )}
2371
+ </CommandGroup>
2372
+ )}
2373
+ </CommandList>
2374
+ </Command>
2375
+ </div>
2368
2376
  </div>
2369
2377
  </div>
2370
2378
  </div>,
package/src/Form.tsx CHANGED
@@ -5305,37 +5305,39 @@ function RecordForm({
5305
5305
  >
5306
5306
  <div className="fixed inset-0 bg-black/50" />
5307
5307
  <div
5308
- className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[90vh] overflow-y-auto border border-border"
5308
+ className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[90vh] overflow-hidden border border-border"
5309
5309
  aria-labelledby="modal-title"
5310
5310
  >
5311
- <div className="flex items-center justify-between mb-4">
5312
- <h2 id="modal-title" className="text-lg font-semibold">
5313
- Create {recordTitle}
5314
- </h2>
5315
- <Button
5316
- type="button"
5317
- variant="ghost"
5318
- size="sm"
5319
- onClick={() => {
5311
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
5312
+ <div className="flex items-center justify-between mb-4">
5313
+ <h2 id="modal-title" className="text-lg font-semibold">
5314
+ Create {recordTitle}
5315
+ </h2>
5316
+ <Button
5317
+ type="button"
5318
+ variant="ghost"
5319
+ size="sm"
5320
+ onClick={() => {
5321
+ setShowDuplicateModal(false)
5322
+ setDuplicateRecordData(undefined)
5323
+ setIsDuplicate(false)
5324
+ }}
5325
+ >
5326
+ <X className="h-4 w-4" />
5327
+ </Button>
5328
+ </div>
5329
+ <RecordForm
5330
+ collection={collection}
5331
+ operation="create"
5332
+ path={collectionPath || [labels.collection]}
5333
+ record={duplicateRecordData as StokerRecord}
5334
+ onSuccess={() => {
5320
5335
  setShowDuplicateModal(false)
5321
5336
  setDuplicateRecordData(undefined)
5322
5337
  setIsDuplicate(false)
5323
5338
  }}
5324
- >
5325
- <X className="h-4 w-4" />
5326
- </Button>
5339
+ />
5327
5340
  </div>
5328
- <RecordForm
5329
- collection={collection}
5330
- operation="create"
5331
- path={collectionPath || [labels.collection]}
5332
- record={duplicateRecordData as StokerRecord}
5333
- onSuccess={() => {
5334
- setShowDuplicateModal(false)
5335
- setDuplicateRecordData(undefined)
5336
- setIsDuplicate(false)
5337
- }}
5338
- />
5339
5341
  </div>
5340
5342
  </div>,
5341
5343
  document.body,
@@ -5354,37 +5356,39 @@ function RecordForm({
5354
5356
  >
5355
5357
  <div className="fixed inset-0 bg-black/50" />
5356
5358
  <div
5357
- className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[90vh] overflow-y-auto border border-border"
5359
+ className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[90vh] overflow-hidden border border-border"
5358
5360
  aria-labelledby="convert-modal-title"
5359
5361
  >
5360
- <div className="flex items-center justify-between mb-4">
5361
- <h2 id="convert-modal-title" className="text-lg font-semibold">
5362
- Convert to {allRecordTitles[convertTargetCollection.labels.collection]}
5363
- </h2>
5364
- <Button
5365
- type="button"
5366
- variant="ghost"
5367
- size="sm"
5368
- onClick={() => {
5362
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
5363
+ <div className="flex items-center justify-between mb-4">
5364
+ <h2 id="convert-modal-title" className="text-lg font-semibold">
5365
+ Convert to {allRecordTitles[convertTargetCollection.labels.collection]}
5366
+ </h2>
5367
+ <Button
5368
+ type="button"
5369
+ variant="ghost"
5370
+ size="sm"
5371
+ onClick={() => {
5372
+ setShowConvertModal(false)
5373
+ setConvertRecordData(undefined)
5374
+ setConvertTargetCollection(undefined)
5375
+ }}
5376
+ >
5377
+ <X className="h-4 w-4" />
5378
+ </Button>
5379
+ </div>
5380
+ <RecordForm
5381
+ collection={convertTargetCollection}
5382
+ operation="create"
5383
+ path={[convertTargetCollection.labels.collection]}
5384
+ record={convertRecordData as StokerRecord}
5385
+ onSuccess={() => {
5369
5386
  setShowConvertModal(false)
5370
5387
  setConvertRecordData(undefined)
5371
5388
  setConvertTargetCollection(undefined)
5372
5389
  }}
5373
- >
5374
- <X className="h-4 w-4" />
5375
- </Button>
5390
+ />
5376
5391
  </div>
5377
- <RecordForm
5378
- collection={convertTargetCollection}
5379
- operation="create"
5380
- path={[convertTargetCollection.labels.collection]}
5381
- record={convertRecordData as StokerRecord}
5382
- onSuccess={() => {
5383
- setShowConvertModal(false)
5384
- setConvertRecordData(undefined)
5385
- setConvertTargetCollection(undefined)
5386
- }}
5387
- />
5388
5392
  </div>
5389
5393
  </div>,
5390
5394
  document.body,
package/src/List.tsx CHANGED
@@ -1615,62 +1615,64 @@ export function List({
1615
1615
  >
1616
1616
  <div className="fixed inset-0 bg-black/50" />
1617
1617
  <div
1618
- className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[90vh] overflow-y-auto border border-border"
1618
+ className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[90vh] overflow-hidden border border-border"
1619
1619
  aria-labelledby="dialog-title"
1620
1620
  >
1621
- <div className="space-y-2">
1622
- <div className="flex justify-between items-center mb-4">
1623
- <h4 id="dialog-title" className="font-medium leading-none">
1624
- Update {collectionTitle || labels.collection}
1625
- </h4>
1626
- <Button
1627
- type="button"
1628
- variant="ghost"
1629
- size="icon"
1630
- className="right-4 top-4"
1631
- onClick={() => {
1621
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
1622
+ <div className="space-y-2">
1623
+ <div className="flex justify-between items-center mb-4">
1624
+ <h4 id="dialog-title" className="font-medium leading-none">
1625
+ Update {collectionTitle || labels.collection}
1626
+ </h4>
1627
+ <Button
1628
+ type="button"
1629
+ variant="ghost"
1630
+ size="icon"
1631
+ className="right-4 top-4"
1632
+ onClick={() => {
1633
+ setIsUpdateDialogOpen(false)
1634
+ setTimeout(() => {
1635
+ updateButtonRef.current?.focus()
1636
+ }, 0)
1637
+
1638
+ localStorage.removeItem(
1639
+ `stoker-draft-${labels.collection}`,
1640
+ )
1641
+ }}
1642
+ >
1643
+ <X className="h-4 w-4" />
1644
+ <span className="sr-only">Close</span>
1645
+ </Button>
1646
+ </div>
1647
+ <RecordForm
1648
+ collection={collection}
1649
+ operation="update-many"
1650
+ path={[labels.collection]}
1651
+ onSuccess={() => {
1632
1652
  setIsUpdateDialogOpen(false)
1633
1653
  setTimeout(() => {
1634
1654
  updateButtonRef.current?.focus()
1635
1655
  }, 0)
1636
-
1637
- localStorage.removeItem(
1638
- `stoker-draft-${labels.collection}`,
1639
- )
1656
+ if (isServerReadOnly) {
1657
+ setBackToStartKey((prev) => prev + 1)
1658
+ }
1659
+ }}
1660
+ onSaveRecord={() => {
1661
+ setOptimisticList()
1640
1662
  }}
1641
- >
1642
- <X className="h-4 w-4" />
1643
- <span className="sr-only">Close</span>
1644
- </Button>
1663
+ rowSelection={Object.keys(rowSelection)
1664
+ .map((row) => {
1665
+ const key = row as unknown as number
1666
+ if (!list) return undefined
1667
+ // eslint-disable-next-line security/detect-object-injection
1668
+ return list[key]
1669
+ })
1670
+ .filter(
1671
+ (record): record is StokerRecord =>
1672
+ record !== undefined,
1673
+ )}
1674
+ />
1645
1675
  </div>
1646
- <RecordForm
1647
- collection={collection}
1648
- operation="update-many"
1649
- path={[labels.collection]}
1650
- onSuccess={() => {
1651
- setIsUpdateDialogOpen(false)
1652
- setTimeout(() => {
1653
- updateButtonRef.current?.focus()
1654
- }, 0)
1655
- if (isServerReadOnly) {
1656
- setBackToStartKey((prev) => prev + 1)
1657
- }
1658
- }}
1659
- onSaveRecord={() => {
1660
- setOptimisticList()
1661
- }}
1662
- rowSelection={Object.keys(rowSelection)
1663
- .map((row) => {
1664
- const key = row as unknown as number
1665
- if (!list) return undefined
1666
- // eslint-disable-next-line security/detect-object-injection
1667
- return list[key]
1668
- })
1669
- .filter(
1670
- (record): record is StokerRecord =>
1671
- record !== undefined,
1672
- )}
1673
- />
1674
1676
  </div>
1675
1677
  </div>
1676
1678
  </div>,
@@ -114,33 +114,35 @@ export const CreateProvider: React.FC<CreateProviderProps> = ({ children }) => {
114
114
  >
115
115
  <div className="fixed inset-0 bg-black/50" />
116
116
  <div
117
- className="relative bg-background sm:rounded-lg p-6 w-full max-w-2xl h-full sm:h-[90vh] overflow-y-auto border border-border"
117
+ className="relative bg-background sm:rounded-lg w-full max-w-2xl h-full sm:h-[90vh] overflow-hidden border border-border"
118
118
  aria-labelledby="modal-title"
119
119
  >
120
- <div className="flex items-center justify-between mb-4">
121
- <h2 id="modal-title" className="text-lg font-semibold">
122
- Create {recordTitle}
123
- </h2>
124
- <Button
125
- type="button"
126
- variant="ghost"
127
- size="sm"
128
- onClick={() => {
120
+ <div className="h-full overflow-y-auto overscroll-contain p-6">
121
+ <div className="flex items-center justify-between mb-4">
122
+ <h2 id="modal-title" className="text-lg font-semibold">
123
+ Create {recordTitle}
124
+ </h2>
125
+ <Button
126
+ type="button"
127
+ variant="ghost"
128
+ size="sm"
129
+ onClick={() => {
130
+ setOpen(false)
131
+ }}
132
+ >
133
+ <X className="h-4 w-4" />
134
+ </Button>
135
+ </div>
136
+ <RecordForm
137
+ collection={currentCollection}
138
+ operation="create"
139
+ path={currentPath}
140
+ record={currentRecord}
141
+ onSuccess={() => {
129
142
  setOpen(false)
130
143
  }}
131
- >
132
- <X className="h-4 w-4" />
133
- </Button>
144
+ />
134
145
  </div>
135
- <RecordForm
136
- collection={currentCollection}
137
- operation="create"
138
- path={currentPath}
139
- record={currentRecord}
140
- onSuccess={() => {
141
- setOpen(false)
142
- }}
143
- />
144
146
  </div>
145
147
  </div>,
146
148
  document.body,