@simplysm/solid 13.0.62 → 13.0.64
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/README.md +6 -0
- package/dist/components/data/crud-detail/CrudDetail.d.ts.map +1 -1
- package/dist/components/data/crud-detail/CrudDetail.js +62 -41
- package/dist/components/data/crud-detail/CrudDetail.js.map +2 -2
- package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +1 -1
- package/dist/components/data/crud-sheet/CrudSheet.js +164 -19
- package/dist/components/data/crud-sheet/CrudSheet.js.map +2 -2
- package/dist/components/data/crud-sheet/types.d.ts +9 -3
- package/dist/components/data/crud-sheet/types.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +3 -2
- package/dist/components/data/sheet/DataSheet.js.map +2 -2
- package/dist/components/form-control/checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.js +10 -10
- package/dist/components/form-control/checkbox/Checkbox.js.map +2 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.styles.js +2 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.js.map +1 -1
- package/dist/components/form-control/checkbox/Radio.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Radio.js +13 -13
- package/dist/components/form-control/checkbox/Radio.js.map +2 -2
- package/dist/components/form-control/data-select-button/DataSelectButton.d.ts +38 -0
- package/dist/components/form-control/data-select-button/DataSelectButton.d.ts.map +1 -0
- package/dist/components/form-control/data-select-button/DataSelectButton.js +184 -0
- package/dist/components/form-control/data-select-button/DataSelectButton.js.map +6 -0
- package/dist/components/form-control/select/Select.d.ts +7 -3
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +146 -45
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/select-list/SelectList.d.ts +54 -0
- package/dist/components/form-control/select-list/SelectList.d.ts.map +1 -0
- package/dist/components/form-control/select-list/SelectList.js +280 -0
- package/dist/components/form-control/select-list/SelectList.js.map +6 -0
- package/dist/components/form-control/select-list/SelectListContext.d.ts +13 -0
- package/dist/components/form-control/select-list/SelectListContext.d.ts.map +1 -0
- package/dist/components/form-control/select-list/SelectListContext.js +14 -0
- package/dist/components/form-control/select-list/SelectListContext.js.map +6 -0
- package/dist/components/form-control/shared-data/SharedDataSelect.d.ts +32 -0
- package/dist/components/form-control/shared-data/SharedDataSelect.d.ts.map +1 -0
- package/dist/components/form-control/shared-data/SharedDataSelect.js +74 -0
- package/dist/components/form-control/shared-data/SharedDataSelect.js.map +6 -0
- package/dist/components/form-control/shared-data/SharedDataSelectButton.d.ts +29 -0
- package/dist/components/form-control/shared-data/SharedDataSelectButton.d.ts.map +1 -0
- package/dist/components/form-control/shared-data/SharedDataSelectButton.js +17 -0
- package/dist/components/form-control/shared-data/SharedDataSelectButton.js.map +6 -0
- package/dist/components/form-control/shared-data/SharedDataSelectList.d.ts +29 -0
- package/dist/components/form-control/shared-data/SharedDataSelectList.d.ts.map +1 -0
- package/dist/components/form-control/shared-data/SharedDataSelectList.js +80 -0
- package/dist/components/form-control/shared-data/SharedDataSelectList.js.map +6 -0
- package/dist/features/address/AddressSearch.d.ts +8 -0
- package/dist/features/address/AddressSearch.d.ts.map +1 -0
- package/dist/features/address/AddressSearch.js +72 -0
- package/dist/features/address/AddressSearch.js.map +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/shared-data/SharedDataContext.d.ts +14 -0
- package/dist/providers/shared-data/SharedDataContext.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataContext.js.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.js +5 -1
- package/dist/providers/shared-data/SharedDataProvider.js.map +2 -2
- package/docs/data-components.md +15 -4
- package/docs/form-controls.md +257 -0
- package/docs/hooks.md +30 -0
- package/docs/providers.md +7 -0
- package/package.json +3 -3
- package/src/components/data/crud-detail/CrudDetail.tsx +51 -26
- package/src/components/data/crud-sheet/CrudSheet.tsx +157 -20
- package/src/components/data/crud-sheet/types.ts +13 -3
- package/src/components/data/sheet/DataSheet.tsx +6 -7
- package/src/components/form-control/checkbox/Checkbox.styles.ts +2 -2
- package/src/components/form-control/checkbox/Checkbox.tsx +18 -20
- package/src/components/form-control/checkbox/Radio.tsx +18 -20
- package/src/components/form-control/data-select-button/DataSelectButton.tsx +279 -0
- package/src/components/form-control/select/Select.tsx +192 -36
- package/src/components/form-control/select-list/SelectList.tsx +385 -0
- package/src/components/form-control/select-list/SelectListContext.ts +23 -0
- package/src/components/form-control/shared-data/SharedDataSelect.tsx +101 -0
- package/src/components/form-control/shared-data/SharedDataSelectButton.tsx +47 -0
- package/src/components/form-control/shared-data/SharedDataSelectList.tsx +85 -0
- package/src/features/address/AddressSearch.tsx +75 -0
- package/src/index.ts +18 -0
- package/src/providers/shared-data/SharedDataContext.ts +14 -0
- package/src/providers/shared-data/SharedDataProvider.tsx +4 -0
package/docs/form-controls.md
CHANGED
|
@@ -436,6 +436,263 @@ import { Select } from "@simplysm/solid";
|
|
|
436
436
|
|
|
437
437
|
---
|
|
438
438
|
|
|
439
|
+
## SelectList
|
|
440
|
+
|
|
441
|
+
List-style single selection component with built-in search, pagination, and slot-based customization. Uses compound component pattern with `SelectList.Header`, `SelectList.Filter`, and `SelectList.ItemTemplate`.
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
import { SelectList } from "@simplysm/solid";
|
|
445
|
+
|
|
446
|
+
// Basic usage with search
|
|
447
|
+
<SelectList
|
|
448
|
+
items={users()}
|
|
449
|
+
value={selectedUser()}
|
|
450
|
+
onValueChange={setSelectedUser}
|
|
451
|
+
getSearchText={(user) => user.name}
|
|
452
|
+
>
|
|
453
|
+
<SelectList.ItemTemplate>
|
|
454
|
+
{(user) => <>{user.name} ({user.email})</>}
|
|
455
|
+
</SelectList.ItemTemplate>
|
|
456
|
+
</SelectList>
|
|
457
|
+
|
|
458
|
+
// With pagination and header
|
|
459
|
+
<SelectList
|
|
460
|
+
items={items()}
|
|
461
|
+
value={selected()}
|
|
462
|
+
onValueChange={setSelected}
|
|
463
|
+
pageSize={20}
|
|
464
|
+
header="Select an item"
|
|
465
|
+
>
|
|
466
|
+
<SelectList.ItemTemplate>
|
|
467
|
+
{(item) => <>{item.name}</>}
|
|
468
|
+
</SelectList.ItemTemplate>
|
|
469
|
+
</SelectList>
|
|
470
|
+
|
|
471
|
+
// With custom header and filter slots
|
|
472
|
+
<SelectList
|
|
473
|
+
items={items()}
|
|
474
|
+
value={selected()}
|
|
475
|
+
onValueChange={setSelected}
|
|
476
|
+
>
|
|
477
|
+
<SelectList.Header>
|
|
478
|
+
<div class="flex items-center gap-1">Custom Header</div>
|
|
479
|
+
</SelectList.Header>
|
|
480
|
+
<SelectList.Filter>
|
|
481
|
+
<MyCustomFilter />
|
|
482
|
+
</SelectList.Filter>
|
|
483
|
+
<SelectList.ItemTemplate>
|
|
484
|
+
{(item) => <>{item.label}</>}
|
|
485
|
+
</SelectList.ItemTemplate>
|
|
486
|
+
</SelectList>
|
|
487
|
+
|
|
488
|
+
// With canChange guard
|
|
489
|
+
<SelectList
|
|
490
|
+
items={items()}
|
|
491
|
+
value={selected()}
|
|
492
|
+
onValueChange={setSelected}
|
|
493
|
+
canChange={async (item) => {
|
|
494
|
+
if (hasUnsavedChanges()) return confirm("Discard changes?");
|
|
495
|
+
return true;
|
|
496
|
+
}}
|
|
497
|
+
>
|
|
498
|
+
<SelectList.ItemTemplate>
|
|
499
|
+
{(item) => <>{item.name}</>}
|
|
500
|
+
</SelectList.ItemTemplate>
|
|
501
|
+
</SelectList>
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
| Prop | Type | Default | Description |
|
|
505
|
+
|------|------|---------|-------------|
|
|
506
|
+
| `items` | `T[]` | **(required)** | Item array |
|
|
507
|
+
| `value` | `T` | - | Selected value |
|
|
508
|
+
| `onValueChange` | `(value: T \| undefined) => void` | - | Value change callback |
|
|
509
|
+
| `required` | `boolean` | - | Required (hides "unspecified" item) |
|
|
510
|
+
| `disabled` | `boolean` | - | Disabled state |
|
|
511
|
+
| `getSearchText` | `(item: T) => string` | - | Search text extractor (auto-shows search input) |
|
|
512
|
+
| `getIsHidden` | `(item: T) => boolean` | - | Hidden item filter |
|
|
513
|
+
| `filterFn` | `(item: T, index: number) => boolean` | - | Custom filter function |
|
|
514
|
+
| `canChange` | `(item: T \| undefined) => boolean \| Promise<boolean>` | - | Change guard (return `false` to block) |
|
|
515
|
+
| `pageSize` | `number` | - | Page size (auto-shows pagination) |
|
|
516
|
+
| `header` | `string` | - | Header text |
|
|
517
|
+
| `class` | `string` | - | CSS class |
|
|
518
|
+
| `style` | `JSX.CSSProperties` | - | Inline style |
|
|
519
|
+
|
|
520
|
+
**Sub-components:**
|
|
521
|
+
- `SelectList.Header` -- Custom header slot (overrides `header` prop)
|
|
522
|
+
- `SelectList.Filter` -- Custom filter slot (overrides default search input)
|
|
523
|
+
- `SelectList.ItemTemplate` -- Item rendering template
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## DataSelectButton
|
|
528
|
+
|
|
529
|
+
Modal-based selection button. Displays selected items inline and opens a dialog for selection. Supports single and multiple selection with key-based loading.
|
|
530
|
+
|
|
531
|
+
```tsx
|
|
532
|
+
import { DataSelectButton, type DataSelectModalResult } from "@simplysm/solid";
|
|
533
|
+
|
|
534
|
+
// Single selection
|
|
535
|
+
<DataSelectButton
|
|
536
|
+
value={selectedUserId()}
|
|
537
|
+
onValueChange={setSelectedUserId}
|
|
538
|
+
load={async (keys) => await api.getUsersByIds(keys)}
|
|
539
|
+
modal={() => <UserSelectModal />}
|
|
540
|
+
renderItem={(user) => <>{user.name}</>}
|
|
541
|
+
/>
|
|
542
|
+
|
|
543
|
+
// Multiple selection
|
|
544
|
+
<DataSelectButton
|
|
545
|
+
value={selectedIds()}
|
|
546
|
+
onValueChange={setSelectedIds}
|
|
547
|
+
multiple
|
|
548
|
+
load={async (keys) => await api.getItemsByIds(keys)}
|
|
549
|
+
modal={() => <ItemSelectModal />}
|
|
550
|
+
renderItem={(item) => <>{item.name}</>}
|
|
551
|
+
/>
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
The modal should return `DataSelectModalResult<TKey>` via `dialogInstance.close({ selectedKeys: [...] })`.
|
|
555
|
+
|
|
556
|
+
| Prop | Type | Default | Description |
|
|
557
|
+
|------|------|---------|-------------|
|
|
558
|
+
| `value` | `TKey \| TKey[]` | - | Selected key(s) |
|
|
559
|
+
| `onValueChange` | `(value: TKey \| TKey[] \| undefined) => void` | - | Value change callback |
|
|
560
|
+
| `load` | `(keys: TKey[]) => TItem[] \| Promise<TItem[]>` | **(required)** | Load items by keys |
|
|
561
|
+
| `modal` | `() => JSX.Element` | **(required)** | Selection modal factory |
|
|
562
|
+
| `renderItem` | `(item: TItem) => JSX.Element` | **(required)** | Item display renderer |
|
|
563
|
+
| `multiple` | `boolean` | - | Multiple selection mode |
|
|
564
|
+
| `required` | `boolean` | - | Required field |
|
|
565
|
+
| `disabled` | `boolean` | - | Disabled state |
|
|
566
|
+
| `size` | `"xs" \| "sm" \| "lg" \| "xl"` | - | Size |
|
|
567
|
+
| `inset` | `boolean` | - | Inset style |
|
|
568
|
+
| `validate` | `(value: unknown) => string \| undefined` | - | Custom validation function |
|
|
569
|
+
| `touchMode` | `boolean` | - | Show error only after focus loss |
|
|
570
|
+
| `dialogOptions` | `DialogShowOptions` | - | Dialog options for modal |
|
|
571
|
+
|
|
572
|
+
**DataSelectModalResult:**
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
interface DataSelectModalResult<TKey> {
|
|
576
|
+
selectedKeys: TKey[];
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
## SharedData Wrappers
|
|
583
|
+
|
|
584
|
+
Convenience wrappers that connect `SharedDataAccessor` (from `useSharedData()`) to `Select`, `DataSelectButton`, and `SelectList` components. They auto-wire `items`, tree structure (`getChildren`), search, and hidden filtering from the shared data definition.
|
|
585
|
+
|
|
586
|
+
### SharedDataSelect
|
|
587
|
+
|
|
588
|
+
Wraps `Select` with `SharedDataAccessor`. Optionally adds search modal and edit modal action buttons.
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
import { SharedDataSelect } from "@simplysm/solid";
|
|
592
|
+
|
|
593
|
+
const sharedData = useSharedData<MySharedData>();
|
|
594
|
+
|
|
595
|
+
<SharedDataSelect data={sharedData.departments} value={deptId()} onValueChange={setDeptId}>
|
|
596
|
+
{(dept) => <>{dept.name}</>}
|
|
597
|
+
</SharedDataSelect>
|
|
598
|
+
|
|
599
|
+
// With search modal and edit modal
|
|
600
|
+
<SharedDataSelect
|
|
601
|
+
data={sharedData.users}
|
|
602
|
+
value={userId()}
|
|
603
|
+
onValueChange={setUserId}
|
|
604
|
+
modal={() => <UserSearchModal />}
|
|
605
|
+
editModal={() => <UserEditModal />}
|
|
606
|
+
>
|
|
607
|
+
{(user) => <>{user.name}</>}
|
|
608
|
+
</SharedDataSelect>
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
| Prop | Type | Default | Description |
|
|
612
|
+
|------|------|---------|-------------|
|
|
613
|
+
| `data` | `SharedDataAccessor<TItem>` | **(required)** | Shared data accessor |
|
|
614
|
+
| `value` | `unknown` | - | Selected value |
|
|
615
|
+
| `onValueChange` | `(value: unknown) => void` | - | Value change callback |
|
|
616
|
+
| `multiple` | `boolean` | - | Multiple selection |
|
|
617
|
+
| `required` | `boolean` | - | Required field |
|
|
618
|
+
| `disabled` | `boolean` | - | Disabled state |
|
|
619
|
+
| `size` | `"xs" \| "sm" \| "lg" \| "xl"` | - | Size |
|
|
620
|
+
| `inset` | `boolean` | - | Inset style |
|
|
621
|
+
| `filterFn` | `(item: TItem, index: number) => boolean` | - | Item filter function |
|
|
622
|
+
| `modal` | `() => JSX.Element` | - | Search modal factory (adds search icon action) |
|
|
623
|
+
| `editModal` | `() => JSX.Element` | - | Edit modal factory (adds edit icon action) |
|
|
624
|
+
| `children` | `(item: TItem, index: number, depth: number) => JSX.Element` | **(required)** | Item render function |
|
|
625
|
+
|
|
626
|
+
### SharedDataSelectButton
|
|
627
|
+
|
|
628
|
+
Wraps `DataSelectButton` with `SharedDataAccessor`. Auto-wires `load` from shared data items.
|
|
629
|
+
|
|
630
|
+
```tsx
|
|
631
|
+
import { SharedDataSelectButton } from "@simplysm/solid";
|
|
632
|
+
|
|
633
|
+
const sharedData = useSharedData<MySharedData>();
|
|
634
|
+
|
|
635
|
+
<SharedDataSelectButton
|
|
636
|
+
data={sharedData.users}
|
|
637
|
+
value={userId()}
|
|
638
|
+
onValueChange={setUserId}
|
|
639
|
+
modal={() => <UserSelectModal />}
|
|
640
|
+
>
|
|
641
|
+
{(user) => <>{user.name}</>}
|
|
642
|
+
</SharedDataSelectButton>
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
| Prop | Type | Default | Description |
|
|
646
|
+
|------|------|---------|-------------|
|
|
647
|
+
| `data` | `SharedDataAccessor<TItem>` | **(required)** | Shared data accessor |
|
|
648
|
+
| `value` | `TKey \| TKey[]` | - | Selected key(s) |
|
|
649
|
+
| `onValueChange` | `(value: TKey \| TKey[] \| undefined) => void` | - | Value change callback |
|
|
650
|
+
| `multiple` | `boolean` | - | Multiple selection |
|
|
651
|
+
| `required` | `boolean` | - | Required field |
|
|
652
|
+
| `disabled` | `boolean` | - | Disabled state |
|
|
653
|
+
| `size` | `"xs" \| "sm" \| "lg" \| "xl"` | - | Size |
|
|
654
|
+
| `inset` | `boolean` | - | Inset style |
|
|
655
|
+
| `modal` | `() => JSX.Element` | **(required)** | Selection modal factory |
|
|
656
|
+
| `children` | `(item: TItem) => JSX.Element` | **(required)** | Item render function |
|
|
657
|
+
|
|
658
|
+
### SharedDataSelectList
|
|
659
|
+
|
|
660
|
+
Wraps `SelectList` with `SharedDataAccessor`. Optionally adds a management modal link in header.
|
|
661
|
+
|
|
662
|
+
```tsx
|
|
663
|
+
import { SharedDataSelectList } from "@simplysm/solid";
|
|
664
|
+
|
|
665
|
+
const sharedData = useSharedData<MySharedData>();
|
|
666
|
+
|
|
667
|
+
<SharedDataSelectList
|
|
668
|
+
data={sharedData.categories}
|
|
669
|
+
value={selectedCategory()}
|
|
670
|
+
onValueChange={setSelectedCategory}
|
|
671
|
+
header="Category"
|
|
672
|
+
modal={() => <CategoryManageModal />}
|
|
673
|
+
>
|
|
674
|
+
<SelectList.ItemTemplate>
|
|
675
|
+
{(cat) => <>{cat.name}</>}
|
|
676
|
+
</SelectList.ItemTemplate>
|
|
677
|
+
</SharedDataSelectList>
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
| Prop | Type | Default | Description |
|
|
681
|
+
|------|------|---------|-------------|
|
|
682
|
+
| `data` | `SharedDataAccessor<TItem>` | **(required)** | Shared data accessor |
|
|
683
|
+
| `value` | `TItem` | - | Selected value |
|
|
684
|
+
| `onValueChange` | `(value: TItem \| undefined) => void` | - | Value change callback |
|
|
685
|
+
| `required` | `boolean` | - | Required field |
|
|
686
|
+
| `disabled` | `boolean` | - | Disabled state |
|
|
687
|
+
| `filterFn` | `(item: TItem, index: number) => boolean` | - | Item filter function |
|
|
688
|
+
| `canChange` | `(item: TItem \| undefined) => boolean \| Promise<boolean>` | - | Change guard |
|
|
689
|
+
| `pageSize` | `number` | - | Page size (auto-shows pagination) |
|
|
690
|
+
| `header` | `string` | - | Header text |
|
|
691
|
+
| `modal` | `() => JSX.Element` | - | Management modal factory (adds link icon in header) |
|
|
692
|
+
| `children` | `JSX.Element` | **(required)** | Sub-component children (e.g., `SelectList.ItemTemplate`) |
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
439
696
|
## Combobox
|
|
440
697
|
|
|
441
698
|
Autocomplete component with async search and item selection support. Debouncing is built-in.
|
package/docs/hooks.md
CHANGED
|
@@ -269,6 +269,36 @@ const {
|
|
|
269
269
|
|
|
270
270
|
---
|
|
271
271
|
|
|
272
|
+
## createSlotSignal
|
|
273
|
+
|
|
274
|
+
Signal factory for slot registration pattern. Used internally by compound components (`SelectList`, etc.) to register child slot content.
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { createSlotSignal, type SlotAccessor } from "@simplysm/solid";
|
|
278
|
+
|
|
279
|
+
const [headerSlot, setHeader] = createSlotSignal();
|
|
280
|
+
|
|
281
|
+
// Register slot content (typically from a sub-component)
|
|
282
|
+
setHeader(() => <div>Header Content</div>);
|
|
283
|
+
|
|
284
|
+
// Read slot content (in parent render)
|
|
285
|
+
<Show when={headerSlot()}>
|
|
286
|
+
{headerSlot()!()}
|
|
287
|
+
</Show>
|
|
288
|
+
|
|
289
|
+
// Unregister
|
|
290
|
+
setHeader(undefined);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
| Return | Type | Description |
|
|
294
|
+
|--------|------|-------------|
|
|
295
|
+
| `[0]` | `Accessor<SlotAccessor>` | Slot accessor (`(() => JSX.Element) \| undefined`) |
|
|
296
|
+
| `[1]` | `(content: SlotAccessor) => void` | Slot setter |
|
|
297
|
+
|
|
298
|
+
**`SlotAccessor` type:** `(() => JSX.Element) | undefined`
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
272
302
|
## useRouterLink
|
|
273
303
|
|
|
274
304
|
`@solidjs/router`-based navigation hook. Automatically handles Ctrl/Alt + click (new tab), Shift + click (new window), and regular click (SPA routing).
|
package/docs/providers.md
CHANGED
|
@@ -106,6 +106,9 @@ interface SharedDataDefinition<TData> {
|
|
|
106
106
|
getKey: (item: TData) => string | number; // Primary key extractor
|
|
107
107
|
orderBy: [(item: TData) => unknown, "asc" | "desc"][]; // Sort order
|
|
108
108
|
filter?: unknown; // Optional filter for change events
|
|
109
|
+
getSearchText?: (item: TData) => string; // Search text extractor (for SelectList/Select filtering)
|
|
110
|
+
getIsHidden?: (item: TData) => boolean; // Hidden item filter
|
|
111
|
+
getParentKey?: (item: TData) => string | number | undefined; // Parent key extractor (for tree structure)
|
|
109
112
|
}
|
|
110
113
|
```
|
|
111
114
|
|
|
@@ -116,6 +119,10 @@ interface SharedDataDefinition<TData> {
|
|
|
116
119
|
| `items` | `Accessor<TData[]>` | Reactive item array |
|
|
117
120
|
| `get` | `(key: string \| number \| undefined) => TData \| undefined` | Get item by key |
|
|
118
121
|
| `emit` | `(changeKeys?: Array<string \| number>) => Promise<void>` | Emit change event to server (triggers refetch in all subscribers) |
|
|
122
|
+
| `getKey` | `(item: TData) => string \| number` | Primary key extractor |
|
|
123
|
+
| `getSearchText` | `((item: TData) => string) \| undefined` | Search text extractor |
|
|
124
|
+
| `getIsHidden` | `((item: TData) => boolean) \| undefined` | Hidden item filter |
|
|
125
|
+
| `getParentKey` | `((item: TData) => string \| number \| undefined) \| undefined` | Parent key extractor (tree structure) |
|
|
119
126
|
|
|
120
127
|
**SharedDataValue extras:**
|
|
121
128
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/solid",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.64",
|
|
4
4
|
"description": "심플리즘 패키지 - SolidJS 라이브러리",
|
|
5
5
|
"author": "김석래",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"solid-tiptap": "^0.8.0",
|
|
51
51
|
"tailwind-merge": "^3.5.0",
|
|
52
52
|
"tailwindcss": "^3.4.19",
|
|
53
|
-
"@simplysm/core-common": "13.0.
|
|
54
|
-
"@simplysm/core-browser": "13.0.
|
|
53
|
+
"@simplysm/core-common": "13.0.64",
|
|
54
|
+
"@simplysm/core-browser": "13.0.64"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@solidjs/testing-library": "^0.8.10"
|
|
@@ -200,6 +200,23 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
200
200
|
저장
|
|
201
201
|
</Button>
|
|
202
202
|
</Show>
|
|
203
|
+
<Show
|
|
204
|
+
when={
|
|
205
|
+
canEdit() && local.toggleDelete && info() && !info()!.isNew && (local.deletable ?? true)
|
|
206
|
+
}
|
|
207
|
+
>
|
|
208
|
+
{(_) => (
|
|
209
|
+
<Button
|
|
210
|
+
size="lg"
|
|
211
|
+
variant="ghost"
|
|
212
|
+
theme="danger"
|
|
213
|
+
onClick={() => void handleToggleDelete()}
|
|
214
|
+
>
|
|
215
|
+
<Icon icon={info()!.isDeleted ? IconTrashOff : IconTrash} class="mr-1" />
|
|
216
|
+
{info()!.isDeleted ? "복구" : "삭제"}
|
|
217
|
+
</Button>
|
|
218
|
+
)}
|
|
219
|
+
</Show>
|
|
203
220
|
<Button size="lg" variant="ghost" theme="info" onClick={() => void handleRefresh()}>
|
|
204
221
|
<Icon icon={IconRefresh} class="mr-1" />
|
|
205
222
|
새로고침
|
|
@@ -255,38 +272,46 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
255
272
|
busy={busyCount() > 0}
|
|
256
273
|
class={clsx("flex h-full flex-col", local.class)}
|
|
257
274
|
>
|
|
258
|
-
{/* Toolbar
|
|
259
|
-
<Show when={!isModal &&
|
|
275
|
+
{/* Toolbar */}
|
|
276
|
+
<Show when={(!isModal && !topbarCtx) || defs().tools}>
|
|
260
277
|
<div class="flex gap-2 p-2 pb-0">
|
|
261
|
-
<Show when={
|
|
262
|
-
<
|
|
263
|
-
size="sm"
|
|
264
|
-
theme="primary"
|
|
265
|
-
variant="ghost"
|
|
266
|
-
onClick={() => formRef?.requestSubmit()}
|
|
267
|
-
>
|
|
268
|
-
<Icon icon={IconDeviceFloppy} class="mr-1" />
|
|
269
|
-
저장
|
|
270
|
-
</Button>
|
|
271
|
-
</Show>
|
|
272
|
-
<Button size="sm" theme="info" variant="ghost" onClick={() => void handleRefresh()}>
|
|
273
|
-
<Icon icon={IconRefresh} class="mr-1" />
|
|
274
|
-
새로고침
|
|
275
|
-
</Button>
|
|
276
|
-
<Show
|
|
277
|
-
when={local.toggleDelete && info() && !info()!.isNew && (local.deletable ?? true)}
|
|
278
|
-
>
|
|
279
|
-
{(_) => (
|
|
278
|
+
<Show when={!topbarCtx && !isModal}>
|
|
279
|
+
<Show when={canEdit() && local.submit}>
|
|
280
280
|
<Button
|
|
281
281
|
size="sm"
|
|
282
|
-
theme="
|
|
282
|
+
theme="primary"
|
|
283
283
|
variant="ghost"
|
|
284
|
-
onClick={() =>
|
|
284
|
+
onClick={() => formRef?.requestSubmit()}
|
|
285
285
|
>
|
|
286
|
-
<Icon icon={
|
|
287
|
-
|
|
286
|
+
<Icon icon={IconDeviceFloppy} class="mr-1" />
|
|
287
|
+
저장
|
|
288
288
|
</Button>
|
|
289
|
-
|
|
289
|
+
</Show>
|
|
290
|
+
<Show
|
|
291
|
+
when={
|
|
292
|
+
canEdit() &&
|
|
293
|
+
local.toggleDelete &&
|
|
294
|
+
info() &&
|
|
295
|
+
!info()!.isNew &&
|
|
296
|
+
(local.deletable ?? true)
|
|
297
|
+
}
|
|
298
|
+
>
|
|
299
|
+
{(_) => (
|
|
300
|
+
<Button
|
|
301
|
+
size="sm"
|
|
302
|
+
theme="danger"
|
|
303
|
+
variant="ghost"
|
|
304
|
+
onClick={() => void handleToggleDelete()}
|
|
305
|
+
>
|
|
306
|
+
<Icon icon={info()!.isDeleted ? IconTrashOff : IconTrash} class="mr-1" />
|
|
307
|
+
{info()!.isDeleted ? "복구" : "삭제"}
|
|
308
|
+
</Button>
|
|
309
|
+
)}
|
|
310
|
+
</Show>
|
|
311
|
+
<Button size="sm" theme="info" variant="ghost" onClick={() => void handleRefresh()}>
|
|
312
|
+
<Icon icon={IconRefresh} class="mr-1" />
|
|
313
|
+
새로고침
|
|
314
|
+
</Button>
|
|
290
315
|
</Show>
|
|
291
316
|
<Show when={defs().tools}>{(toolsDef) => toolsDef().children}</Show>
|
|
292
317
|
</div>
|