@spaceinvoices/react-ui 0.4.8 → 0.4.11
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 +24 -8
- package/cli/dist/index.js +89 -26
- package/package.json +4 -1
- package/spaceinvoices.schema.json +6 -1
- package/src/common/autocomplete.tsx +69 -6
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +124 -285
- package/src/components/advance-invoices/list/list-table.tsx +10 -3
- package/src/components/advance-invoices/list/locales/de.ts +2 -0
- package/src/components/advance-invoices/list/locales/en.ts +1 -0
- package/src/components/advance-invoices/list/locales/es.ts +1 -0
- package/src/components/advance-invoices/list/locales/fr.ts +1 -0
- package/src/components/advance-invoices/list/locales/hr.ts +1 -0
- package/src/components/advance-invoices/list/locales/it.ts +1 -0
- package/src/components/advance-invoices/list/locales/nl.ts +1 -0
- package/src/components/advance-invoices/list/locales/pl.ts +1 -0
- package/src/components/advance-invoices/list/locales/pt.ts +1 -0
- package/src/components/advance-invoices/list/locales/sl.ts +1 -0
- package/src/components/advance-invoices/list/use-advance-invoice-download.ts +1 -12
- package/src/components/credit-notes/create/create-credit-note-form.tsx +116 -238
- package/src/components/credit-notes/list/list-table.tsx +6 -3
- package/src/components/credit-notes/list/use-credit-note-download.ts +1 -12
- package/src/components/customers/customer-autocomplete.tsx +64 -11
- package/src/components/customers/customer-list-table/customer-list-table.tsx +3 -2
- package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +9 -1
- package/src/components/dashboard/collection-rate-card/locales/bg.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/cs.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/et.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/fi.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/is.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/nb.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/sk.ts +3 -0
- package/src/components/dashboard/collection-rate-card/locales/sv.ts +3 -0
- package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +10 -2
- package/src/components/dashboard/invoice-status-chart/locales/bg.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/cs.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/de.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/es.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/et.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/fi.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/fr.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/hr.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/is.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/it.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/nb.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/nl.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/pl.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/pt.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/sk.ts +10 -0
- package/src/components/dashboard/invoice-status-chart/locales/sl.ts +1 -0
- package/src/components/dashboard/invoice-status-chart/locales/sv.ts +10 -0
- package/src/components/dashboard/payment-methods-chart/locales/bg.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/cs.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/et.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/fi.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/is.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/nb.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/sk.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/locales/sv.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +9 -1
- package/src/components/dashboard/payment-trend-chart/locales/bg.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/cs.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/de.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/es.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/et.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/fi.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/fr.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/hr.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/is.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/it.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/nb.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/nl.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/pl.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/pt.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/sk.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/locales/sl.ts +1 -0
- package/src/components/dashboard/payment-trend-chart/locales/sv.ts +6 -0
- package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +15 -8
- package/src/components/dashboard/revenue-trend-chart/locales/bg.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/cs.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/de.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/es.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/et.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/fi.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/fr.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/hr.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/is.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/it.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/nb.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/nl.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/pl.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/pt.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/sk.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +1 -0
- package/src/components/dashboard/revenue-trend-chart/locales/sv.ts +6 -0
- package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +15 -8
- package/src/components/dashboard/tax-collected-card/locales.ts +110 -0
- package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +8 -2
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +4 -4
- package/src/components/dashboard/top-customers-chart/locales/bg.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/cs.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/de.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/es.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/et.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/fi.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/fr.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/hr.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/is.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/it.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/nb.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/nl.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/pl.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/pt.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/sk.ts +7 -0
- package/src/components/dashboard/top-customers-chart/locales/sl.ts +2 -0
- package/src/components/dashboard/top-customers-chart/locales/sv.ts +7 -0
- package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +23 -12
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +33 -20
- package/src/components/delivery-notes/list/list-table.tsx +22 -13
- package/src/components/delivery-notes/list/locales/de.ts +2 -0
- package/src/components/delivery-notes/list/locales/en.ts +1 -0
- package/src/components/delivery-notes/list/locales/es.ts +1 -0
- package/src/components/delivery-notes/list/locales/fr.ts +1 -0
- package/src/components/delivery-notes/list/locales/hr.ts +1 -0
- package/src/components/delivery-notes/list/locales/it.ts +1 -0
- package/src/components/delivery-notes/list/locales/nl.ts +1 -0
- package/src/components/delivery-notes/list/locales/pl.ts +1 -0
- package/src/components/delivery-notes/list/locales/pt.ts +1 -0
- package/src/components/delivery-notes/list/locales/sl.ts +1 -0
- package/src/components/delivery-notes/list/use-delivery-note-download.ts +1 -12
- package/src/components/documents/create/document-add-item-form.tsx +28 -16
- package/src/components/documents/create/document-add-item-tax-rate-field.tsx +12 -2
- package/src/components/documents/create/document-items-section.tsx +70 -39
- package/src/components/documents/create/document-recipient-section.tsx +10 -1
- package/src/components/documents/create/live-preview.tsx +113 -15
- package/src/components/documents/create/prepare-document-submission.ts +35 -16
- package/src/components/documents/create/use-document-customer-form.ts +14 -3
- package/src/components/documents/documents.hooks.ts +7 -2
- package/src/components/documents/shared/document-preview-display.tsx +136 -67
- package/src/components/documents/shared/scaled-document-preview.tsx +45 -5
- package/src/components/documents/view/document-actions-bar.tsx +284 -182
- package/src/components/documents/view/document-activities-list.tsx +3 -0
- package/src/components/documents/view/document-payments-list.tsx +3 -0
- package/src/components/documents/view/locales/de.ts +8 -0
- package/src/components/documents/view/locales/es.ts +8 -0
- package/src/components/documents/view/locales/fr.ts +8 -0
- package/src/components/documents/view/locales/hr.ts +8 -0
- package/src/components/documents/view/locales/it.ts +8 -0
- package/src/components/documents/view/locales/nl.ts +8 -0
- package/src/components/documents/view/locales/pl.ts +8 -0
- package/src/components/documents/view/locales/pt.ts +8 -0
- package/src/components/documents/view/locales/sl.ts +8 -0
- package/src/components/documents/view/use-document-download.ts +14 -25
- package/src/components/entities/create-entity-form.tsx +101 -16
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +10 -10
- package/src/components/entities/entity-settings-form/locales/de.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/es.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/fr.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/hr.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/it.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/nl.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/pl.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/pt.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +10 -0
- package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +3 -3
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +78 -124
- package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +8 -1
- package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +14 -2
- package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +7 -2
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +56 -130
- package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +8 -1
- package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +1 -0
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +15 -2
- package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +20 -3
- package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +38 -12
- package/src/components/entities/settings/defaults-settings-form.tsx +6 -6
- package/src/components/entities/settings/eslog-settings-form.tsx +13 -1
- package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +3 -22
- package/src/components/entities/shared/fiscalization-step-flow.ts +77 -0
- package/src/components/entities/shared/fiscalization-step-tabs.tsx +71 -0
- package/src/components/estimates/create/create-estimate-form.tsx +34 -21
- package/src/components/estimates/list/list-table.tsx +23 -14
- package/src/components/estimates/list/locales/de.ts +2 -0
- package/src/components/estimates/list/locales/en.ts +1 -0
- package/src/components/estimates/list/locales/es.ts +1 -0
- package/src/components/estimates/list/locales/fr.ts +1 -0
- package/src/components/estimates/list/locales/hr.ts +1 -0
- package/src/components/estimates/list/locales/it.ts +1 -0
- package/src/components/estimates/list/locales/nl.ts +1 -0
- package/src/components/estimates/list/locales/pl.ts +1 -0
- package/src/components/estimates/list/locales/pt.ts +1 -0
- package/src/components/estimates/list/locales/sl.ts +1 -0
- package/src/components/estimates/list/use-estimate-download.ts +1 -12
- package/src/components/export/document-export-form.tsx +33 -7
- package/src/components/export/sales-per-item-export-form.tsx +23 -7
- package/src/components/invoices/create/create-invoice-form.tsx +295 -329
- package/src/components/invoices/create/prepare-invoice-submission.ts +0 -8
- package/src/components/invoices/list/list-table.tsx +7 -4
- package/src/components/invoices/list/use-invoice-download.ts +1 -11
- package/src/components/invoices/send-email-dialog/locales/de.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/es.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/fr.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/hr.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/it.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/nl.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/pl.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/pt.ts +20 -0
- package/src/components/invoices/send-email-dialog/locales/sl.ts +20 -0
- package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +77 -8
- package/src/components/invoices/view/eslog-info-display.tsx +17 -1
- package/src/components/invoices/view/fiscalization-status-card.tsx +7 -3
- package/src/components/items/item-combobox.tsx +26 -6
- package/src/components/items/item-list-table/item-list-table.tsx +5 -2
- package/src/components/payments/create-payment-form/index.ts +1 -0
- package/src/components/payments/list/list-table.tsx +14 -4
- package/src/components/recurring-invoices/list/list-table.tsx +7 -4
- package/src/components/request-logs/locales.ts +412 -0
- package/src/components/request-logs/request-log-detail.tsx +37 -21
- package/src/components/request-logs/request-log-list-table.tsx +57 -11
- package/src/components/table/data-table.tsx +5 -2
- package/src/components/table/date-cell.tsx +3 -1
- package/src/components/table/filter-bar.tsx +14 -2
- package/src/components/table/hooks/use-table-query.ts +1 -1
- package/src/components/table/locales.ts +1116 -0
- package/src/components/table/search-input.tsx +12 -3
- package/src/components/table/selection-toolbar.tsx +23 -6
- package/src/components/table/table-empty-state.tsx +43 -3
- package/src/components/table/table-no-results.tsx +3 -3
- package/src/components/table/table-pagination.tsx +4 -3
- package/src/components/table/types.ts +1 -0
- package/src/components/tax-reports/index.ts +1 -0
- package/src/components/tax-reports/kir-export-form.tsx +46 -8
- package/src/components/tax-reports/slovenia-tax-profile-step.tsx +191 -0
- package/src/components/tax-reports/slovenia-yearly-export-form.tsx +509 -0
- package/src/components/tax-reports/slovenia-yearly-review-step.tsx +253 -0
- package/src/components/tax-reports/slovenia-yearly-summary.tsx +19 -0
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -2
- package/src/components/ui/sidebar.tsx +3 -2
- package/src/components/ui/sticky-form-footer.tsx +7 -1
- package/src/components/webhook-logs/index.ts +6 -0
- package/src/components/webhook-logs/locales.ts +392 -0
- package/src/components/webhook-logs/webhook-delivery-detail.tsx +255 -0
- package/src/components/webhook-logs/webhook-delivery-list-table.tsx +278 -0
- package/src/components/wl-subscription/index.ts +1 -0
- package/src/components/wl-subscription/locked-feature.tsx +1 -0
- package/src/components/wl-subscription/paywall.tsx +193 -0
- package/src/components/wl-subscription/upgrade-modal.tsx +93 -29
- package/src/generate-schemas.ts +12 -7
- package/src/generated/schemas/customer.ts +2 -0
- package/src/generated/schemas/entity.ts +134 -0
- package/src/generated/schemas/exportsloveniayearlynormiranireport_body.ts +27 -0
- package/src/generated/schemas/index.ts +2 -0
- package/src/generated/schemas/me.ts +20 -1
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +40 -34
- package/src/generated/schemas/rendercreditnotepreview_body.ts +42 -36
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +23 -13
- package/src/generated/schemas/renderestimatepreview_body.ts +23 -13
- package/src/generated/schemas/renderinvoicepreview_body.ts +40 -34
- package/src/generated/schemas/sendemail_body.ts +44 -0
- package/src/generated/schemas/sloveniataxprofile.ts +42 -0
- package/src/generated/schemas/startpdfexport_body.ts +91 -1
- package/src/generated/schemas/webhook.ts +10 -0
- package/src/hooks/use-duplicate-document.ts +51 -13
- package/src/hooks/use-eslog-validation.ts +59 -0
- package/src/hooks/use-premise-selection.ts +186 -0
- package/src/lib/browser-cookies.ts +4 -4
- package/src/lib/date-fns-locale.ts +48 -0
- package/src/lib/fiscalization-options.ts +81 -0
- package/src/lib/locale.ts +38 -0
- package/src/lib/template-variables.tsx +1 -1
- package/src/lib/translation.ts +14 -3
- package/src/providers/entities-context.tsx +1 -0
- package/src/providers/entities-provider.tsx +102 -3
- package/src/providers/form-footer-context.tsx +37 -4
- package/src/providers/sdk-provider.tsx +7 -2
- package/src/providers/white-label-provider.tsx +4 -1
- package/src/providers/wl-subscription-provider.tsx +90 -3
package/README.md
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
# @spaceinvoices/react-ui - Space Invoices
|
|
1
|
+
# @spaceinvoices/react-ui - Space Invoices React UI Kit
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Copy-paste React UI for the Space Invoices API**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
50+ installable components for building invoicing applications with the Space Invoices API. Includes forms, tables, dashboard charts, and more - all designed to be copied into your project for full customization.
|
|
6
6
|
|
|
7
7
|
## Philosophy
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This package is a **CLI installer and source registry**, not a conventional runtime component library. The intended flow is:
|
|
10
|
+
|
|
11
|
+
1. initialize your app with the CLI
|
|
12
|
+
2. add only the components you need
|
|
13
|
+
3. own the copied source inside your app
|
|
14
|
+
|
|
15
|
+
These components are **designed to be copied**, not imported from `node_modules` at runtime:
|
|
10
16
|
|
|
11
17
|
- **Full ownership** - Modify freely without breaking changes
|
|
12
18
|
- **Complete customization** - Change behavior and structure
|
|
13
19
|
- **No version conflicts** - You control when to update
|
|
14
20
|
- **Zero lock-in** - Components work standalone in your codebase
|
|
15
21
|
|
|
16
|
-
**Note**: Components are built on **shadcn/ui primitives**. Bring your own shadcn/ui components or use any alternative. The `components/ui/`
|
|
22
|
+
**Note**: Components are built on **shadcn/ui primitives**. Bring your own shadcn/ui components or use any alternative. The CLI can copy compatible `components/ui/` primitives when needed, but teams using their own design system can swap those imports after install.
|
|
17
23
|
|
|
18
24
|
## Quick Start (CLI - Recommended)
|
|
19
25
|
|
|
@@ -36,6 +42,7 @@ The CLI will:
|
|
|
36
42
|
- Create `spaceinvoices.json` config with your preferred paths
|
|
37
43
|
- Install required dependencies (`@spaceinvoices/js-sdk`, `@tanstack/react-query`)
|
|
38
44
|
- Copy essential files (SDK provider, utilities)
|
|
45
|
+
- Copy generated Zod schemas when installed components depend on them
|
|
39
46
|
- Transform import paths to match your project structure
|
|
40
47
|
- Install npm dependencies for each component
|
|
41
48
|
|
|
@@ -101,7 +108,10 @@ cp -r react-ui/src/components/customers/ your-project/src/components/space-invoi
|
|
|
101
108
|
cp -r react-ui/src/components/table/ your-project/src/components/space-invoices/
|
|
102
109
|
# ... add more as needed
|
|
103
110
|
|
|
104
|
-
#
|
|
111
|
+
# Include generated schemas if you use form components
|
|
112
|
+
cp -r react-ui/src/generated/ your-project/src/generated/
|
|
113
|
+
|
|
114
|
+
# Optional: skip components/ui/ if you already use shadcn/ui or your own primitives
|
|
105
115
|
```
|
|
106
116
|
|
|
107
117
|
### 4. Update Import Paths
|
|
@@ -158,9 +168,13 @@ src/components/
|
|
|
158
168
|
└── table/ # Generic data table infrastructure
|
|
159
169
|
```
|
|
160
170
|
|
|
161
|
-
### UI Primitives (
|
|
171
|
+
### UI Primitives (Optional)
|
|
172
|
+
|
|
173
|
+
The `components/ui/` folder contains shadcn/ui-style components. You can:
|
|
162
174
|
|
|
163
|
-
|
|
175
|
+
- let the CLI install compatible primitives for you
|
|
176
|
+
- use shadcn/ui directly
|
|
177
|
+
- swap to your own component library after copying the feature components
|
|
164
178
|
|
|
165
179
|
```bash
|
|
166
180
|
npx shadcn@latest add button input form table dialog select
|
|
@@ -175,6 +189,8 @@ src/
|
|
|
175
189
|
├── providers/
|
|
176
190
|
│ ├── sdk-provider.tsx # SDK context (required)
|
|
177
191
|
│ └── entities-provider.tsx # Active entity context (required)
|
|
192
|
+
├── generated/
|
|
193
|
+
│ └── schemas/ # Generated Zod schemas used by form components
|
|
178
194
|
├── hooks/
|
|
179
195
|
│ └── *.ts # Shared hooks
|
|
180
196
|
└── lib/
|
package/cli/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// cli/src/commands/init.ts
|
|
7
7
|
import fs4 from "fs";
|
|
8
|
-
import
|
|
8
|
+
import path5 from "path";
|
|
9
9
|
import prompts from "prompts";
|
|
10
10
|
|
|
11
11
|
// cli/src/utils/config.ts
|
|
@@ -19,7 +19,8 @@ var DEFAULT_CONFIG = {
|
|
|
19
19
|
ui: "@/components/ui",
|
|
20
20
|
lib: "@/lib",
|
|
21
21
|
hooks: "@/hooks",
|
|
22
|
-
providers: "@/providers"
|
|
22
|
+
providers: "@/providers",
|
|
23
|
+
generated: "@/generated"
|
|
23
24
|
}
|
|
24
25
|
};
|
|
25
26
|
function getConfigPath(cwd = process.cwd()) {
|
|
@@ -44,6 +45,20 @@ function writeConfig(config, cwd = process.cwd()) {
|
|
|
44
45
|
const configPath = getConfigPath(cwd);
|
|
45
46
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
46
47
|
}
|
|
48
|
+
function resolveAliasPath(alias, cwd = process.cwd()) {
|
|
49
|
+
if (path.isAbsolute(alias)) {
|
|
50
|
+
return alias;
|
|
51
|
+
}
|
|
52
|
+
if (alias.startsWith("@/")) {
|
|
53
|
+
const srcPath = path.join(cwd, "src", alias.slice(2));
|
|
54
|
+
const rootPath = path.join(cwd, alias.slice(2));
|
|
55
|
+
if (fs.existsSync(path.join(cwd, "src"))) {
|
|
56
|
+
return srcPath;
|
|
57
|
+
}
|
|
58
|
+
return rootPath;
|
|
59
|
+
}
|
|
60
|
+
return path.join(cwd, alias);
|
|
61
|
+
}
|
|
47
62
|
|
|
48
63
|
// cli/src/utils/installer.ts
|
|
49
64
|
import { spawn } from "child_process";
|
|
@@ -268,6 +283,7 @@ function getComponentsByCategory(registry) {
|
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
// cli/src/utils/transformer.ts
|
|
286
|
+
import path4 from "path";
|
|
271
287
|
function transformImports(source, config) {
|
|
272
288
|
let result = source;
|
|
273
289
|
const replacements = [
|
|
@@ -280,7 +296,9 @@ function transformImports(source, config) {
|
|
|
280
296
|
// Lib utilities: @/ui/lib/ -> config.aliases.lib/
|
|
281
297
|
[/@\/ui\/lib\//g, `${config.aliases.lib}/`],
|
|
282
298
|
// Hooks: @/ui/hooks/ -> config.aliases.hooks/
|
|
283
|
-
[/@\/ui\/hooks\//g, `${config.aliases.hooks}/`]
|
|
299
|
+
[/@\/ui\/hooks\//g, `${config.aliases.hooks}/`],
|
|
300
|
+
// Generated helpers: @/ui/generated/ -> config.aliases.generated/
|
|
301
|
+
[/@\/ui\/generated\//g, `${config.aliases.generated}/`]
|
|
284
302
|
];
|
|
285
303
|
for (const [pattern, replacement] of replacements) {
|
|
286
304
|
result = result.replace(pattern, replacement);
|
|
@@ -318,6 +336,12 @@ function getDestinationPath(sourcePath, config) {
|
|
|
318
336
|
category: "hooks"
|
|
319
337
|
};
|
|
320
338
|
}
|
|
339
|
+
if (sourcePath.startsWith("generated/")) {
|
|
340
|
+
return {
|
|
341
|
+
destPath: sourcePath.replace("generated/", ""),
|
|
342
|
+
category: "generated"
|
|
343
|
+
};
|
|
344
|
+
}
|
|
321
345
|
return {
|
|
322
346
|
destPath: sourcePath,
|
|
323
347
|
category: "components"
|
|
@@ -326,13 +350,7 @@ function getDestinationPath(sourcePath, config) {
|
|
|
326
350
|
function getFullDestinationPath(sourcePath, config, basePath) {
|
|
327
351
|
const { destPath, category } = getDestinationPath(sourcePath, config);
|
|
328
352
|
const alias = config.aliases[category];
|
|
329
|
-
|
|
330
|
-
if (alias.startsWith("@/")) {
|
|
331
|
-
relativePath = alias.slice(2);
|
|
332
|
-
} else {
|
|
333
|
-
relativePath = alias;
|
|
334
|
-
}
|
|
335
|
-
return `${basePath}/src/${relativePath}/${destPath}`;
|
|
353
|
+
return path4.join(resolveAliasPath(alias, basePath), destPath);
|
|
336
354
|
}
|
|
337
355
|
|
|
338
356
|
// cli/src/commands/init.ts
|
|
@@ -397,6 +415,12 @@ async function init(options = {}) {
|
|
|
397
415
|
name: "providers",
|
|
398
416
|
message: "Where should providers be installed?",
|
|
399
417
|
initial: DEFAULT_CONFIG.aliases.providers
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
type: "text",
|
|
421
|
+
name: "generated",
|
|
422
|
+
message: "Where should generated helpers (schemas) be installed?",
|
|
423
|
+
initial: DEFAULT_CONFIG.aliases.generated
|
|
400
424
|
}
|
|
401
425
|
]);
|
|
402
426
|
if (!answers.components) {
|
|
@@ -410,7 +434,8 @@ async function init(options = {}) {
|
|
|
410
434
|
ui: answers.ui,
|
|
411
435
|
lib: answers.lib,
|
|
412
436
|
hooks: answers.hooks,
|
|
413
|
-
providers: answers.providers
|
|
437
|
+
providers: answers.providers,
|
|
438
|
+
generated: answers.generated
|
|
414
439
|
}
|
|
415
440
|
};
|
|
416
441
|
}
|
|
@@ -431,16 +456,11 @@ async function init(options = {}) {
|
|
|
431
456
|
config.aliases.ui,
|
|
432
457
|
config.aliases.lib,
|
|
433
458
|
config.aliases.hooks,
|
|
434
|
-
config.aliases.providers
|
|
459
|
+
config.aliases.providers,
|
|
460
|
+
config.aliases.generated
|
|
435
461
|
];
|
|
436
462
|
for (const alias of directories) {
|
|
437
|
-
|
|
438
|
-
if (alias.startsWith("@/")) {
|
|
439
|
-
dirPath = path4.join(cwd, "src", alias.slice(2));
|
|
440
|
-
} else {
|
|
441
|
-
dirPath = path4.join(cwd, alias);
|
|
442
|
-
}
|
|
443
|
-
fs4.mkdirSync(dirPath, { recursive: true });
|
|
463
|
+
fs4.mkdirSync(resolveAliasPath(alias, cwd), { recursive: true });
|
|
444
464
|
}
|
|
445
465
|
dirSpinner.succeed("Created directories");
|
|
446
466
|
} catch (error) {
|
|
@@ -454,7 +474,7 @@ async function init(options = {}) {
|
|
|
454
474
|
const content = await fetchFile(filePath);
|
|
455
475
|
const transformed = transformImports(content, config);
|
|
456
476
|
const destPath = getFullDestinationPath(filePath, config, cwd);
|
|
457
|
-
fs4.mkdirSync(
|
|
477
|
+
fs4.mkdirSync(path5.dirname(destPath), { recursive: true });
|
|
458
478
|
fs4.writeFileSync(destPath, transformed);
|
|
459
479
|
}
|
|
460
480
|
filesSpinner.succeed(`Copied ${ESSENTIAL_FILES.length} essential files`);
|
|
@@ -488,7 +508,7 @@ async function init(options = {}) {
|
|
|
488
508
|
|
|
489
509
|
// cli/src/commands/add.ts
|
|
490
510
|
import fs5 from "fs";
|
|
491
|
-
import
|
|
511
|
+
import path6 from "path";
|
|
492
512
|
import prompts2 from "prompts";
|
|
493
513
|
|
|
494
514
|
// cli/src/utils/resolver.ts
|
|
@@ -614,6 +634,31 @@ function getInstallSummary(resolved) {
|
|
|
614
634
|
};
|
|
615
635
|
}
|
|
616
636
|
|
|
637
|
+
// cli/src/utils/file-dependencies.ts
|
|
638
|
+
var GENERATED_IMPORT_PATTERN = /from\s+["']@\/ui\/generated\/schemas(?:\/([^"']+))?["']/g;
|
|
639
|
+
var GENERATED_EXPORT_PATTERN = /from\s+['"]\.\/([^'"]+)['"]/g;
|
|
640
|
+
function normalizeGeneratedPath(subpath) {
|
|
641
|
+
return `generated/schemas/${subpath.replace(/\.ts$/, "")}.ts`;
|
|
642
|
+
}
|
|
643
|
+
function getRegistryManagedDependencies(filePath, source) {
|
|
644
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
645
|
+
if (filePath === "generated/schemas/index.ts") {
|
|
646
|
+
for (const match of source.matchAll(GENERATED_EXPORT_PATTERN)) {
|
|
647
|
+
dependencies.add(normalizeGeneratedPath(match[1]));
|
|
648
|
+
}
|
|
649
|
+
return [...dependencies];
|
|
650
|
+
}
|
|
651
|
+
for (const match of source.matchAll(GENERATED_IMPORT_PATTERN)) {
|
|
652
|
+
const subpath = match[1];
|
|
653
|
+
if (subpath) {
|
|
654
|
+
dependencies.add(normalizeGeneratedPath(subpath));
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
dependencies.add("generated/schemas/index.ts");
|
|
658
|
+
}
|
|
659
|
+
return [...dependencies];
|
|
660
|
+
}
|
|
661
|
+
|
|
617
662
|
// cli/src/commands/add.ts
|
|
618
663
|
async function add(componentNames, options = {}) {
|
|
619
664
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -674,6 +719,7 @@ async function add(componentNames, options = {}) {
|
|
|
674
719
|
resolveSpinner.fail("Failed to resolve dependencies");
|
|
675
720
|
throw error;
|
|
676
721
|
}
|
|
722
|
+
const fileContents = await collectRegistryFiles(resolved.allFiles);
|
|
677
723
|
const summary = getInstallSummary(resolved);
|
|
678
724
|
logger.break();
|
|
679
725
|
logger.info("The following will be installed:");
|
|
@@ -692,7 +738,7 @@ async function add(componentNames, options = {}) {
|
|
|
692
738
|
` ${highlight("npm packages:")} ${summary.npmPackages.join(", ")}`
|
|
693
739
|
);
|
|
694
740
|
}
|
|
695
|
-
logger.log(` ${highlight("Files:")} ${
|
|
741
|
+
logger.log(` ${highlight("Files:")} ${fileContents.size} files`);
|
|
696
742
|
if (!options.yes) {
|
|
697
743
|
logger.break();
|
|
698
744
|
const { proceed } = await prompts2({
|
|
@@ -712,12 +758,11 @@ async function add(componentNames, options = {}) {
|
|
|
712
758
|
const existingFiles = [];
|
|
713
759
|
const filesToWrite = [];
|
|
714
760
|
try {
|
|
715
|
-
for (const filePath of
|
|
761
|
+
for (const [filePath, content] of fileContents) {
|
|
716
762
|
const destPath = getFullDestinationPath(filePath, config, cwd);
|
|
717
763
|
if (fs5.existsSync(destPath)) {
|
|
718
764
|
existingFiles.push(destPath);
|
|
719
765
|
}
|
|
720
|
-
const content = await fetchFile(filePath);
|
|
721
766
|
const transformed = transformImports(content, config);
|
|
722
767
|
filesToWrite.push({ path: destPath, content: transformed });
|
|
723
768
|
}
|
|
@@ -753,7 +798,7 @@ async function add(componentNames, options = {}) {
|
|
|
753
798
|
}
|
|
754
799
|
try {
|
|
755
800
|
for (const { path: filePath, content } of filesToWrite) {
|
|
756
|
-
fs5.mkdirSync(
|
|
801
|
+
fs5.mkdirSync(path6.dirname(filePath), { recursive: true });
|
|
757
802
|
fs5.writeFileSync(filePath, content);
|
|
758
803
|
}
|
|
759
804
|
filesSpinner.succeed(`Installed ${filesToWrite.length} files`);
|
|
@@ -780,6 +825,24 @@ async function add(componentNames, options = {}) {
|
|
|
780
825
|
logger.success("Components installed successfully!");
|
|
781
826
|
logger.break();
|
|
782
827
|
}
|
|
828
|
+
async function collectRegistryFiles(initialFiles) {
|
|
829
|
+
const pending = [...initialFiles];
|
|
830
|
+
const contents = /* @__PURE__ */ new Map();
|
|
831
|
+
while (pending.length > 0) {
|
|
832
|
+
const filePath = pending.shift();
|
|
833
|
+
if (!filePath || contents.has(filePath)) {
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
const content = await fetchFile(filePath);
|
|
837
|
+
contents.set(filePath, content);
|
|
838
|
+
for (const dependency of getRegistryManagedDependencies(filePath, content)) {
|
|
839
|
+
if (!contents.has(dependency)) {
|
|
840
|
+
pending.push(dependency);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return contents;
|
|
845
|
+
}
|
|
783
846
|
async function selectComponents(registry) {
|
|
784
847
|
const byCategory = getComponentsByCategory(registry);
|
|
785
848
|
const choices = [];
|
|
@@ -870,7 +933,7 @@ async function list(options = {}) {
|
|
|
870
933
|
|
|
871
934
|
// cli/src/index.ts
|
|
872
935
|
var program = new Command();
|
|
873
|
-
program.name("spaceinvoices-ui").description("CLI for adding Space Invoices React UI components to your project").version("0.4.
|
|
936
|
+
program.name("spaceinvoices-ui").description("CLI for adding Space Invoices React UI components to your project").version("0.4.11");
|
|
874
937
|
program.option("--local <path>", "Use local registry from specified path (for development)");
|
|
875
938
|
program.command("init").description("Initialize Space Invoices UI in your project").option("-y, --yes", "Skip prompts and use defaults").option("-f, --force", "Overwrite existing configuration").option("--cwd <path>", "Working directory (defaults to current directory)").action(async (options) => {
|
|
876
939
|
const globalOpts = program.opts();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spaceinvoices/react-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.11",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"description": "Space Invoices UI components - copy-paste distribution with CLI support",
|
|
@@ -78,6 +78,9 @@
|
|
|
78
78
|
"zod": "^4.1.12"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
+
"@happy-dom/global-registrator": "^20.8.3",
|
|
82
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
83
|
+
"@testing-library/react": "^16.3.2",
|
|
81
84
|
"@types/bun": "latest",
|
|
82
85
|
"@types/prompts": "^2.4.9",
|
|
83
86
|
"@types/react": "^19.1.0",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"aliases": {
|
|
13
13
|
"type": "object",
|
|
14
14
|
"description": "Path aliases for component installation",
|
|
15
|
-
"required": ["components", "ui", "lib", "hooks", "providers"],
|
|
15
|
+
"required": ["components", "ui", "lib", "hooks", "providers", "generated"],
|
|
16
16
|
"properties": {
|
|
17
17
|
"components": {
|
|
18
18
|
"type": "string",
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"type": "string",
|
|
39
39
|
"description": "Path alias for React providers (e.g., @/providers)",
|
|
40
40
|
"default": "@/providers"
|
|
41
|
+
},
|
|
42
|
+
"generated": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "Path alias for generated helpers such as Zod schemas (e.g., @/generated)",
|
|
45
|
+
"default": "@/generated"
|
|
41
46
|
}
|
|
42
47
|
},
|
|
43
48
|
"additionalProperties": false
|
|
@@ -14,6 +14,9 @@ type AutocompleteProps = {
|
|
|
14
14
|
value?: string;
|
|
15
15
|
onValueChange?: (value: string) => void;
|
|
16
16
|
onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void; // Added onBlur prop
|
|
17
|
+
onCommitUnselectedInput?: (value: string) => void;
|
|
18
|
+
commitUnselectedOnBlur?: boolean;
|
|
19
|
+
committedDisplayValue?: string;
|
|
17
20
|
placeholder?: string;
|
|
18
21
|
emptyText?: string;
|
|
19
22
|
className?: string;
|
|
@@ -22,6 +25,8 @@ type AutocompleteProps = {
|
|
|
22
25
|
onSearch?: (value: string) => void;
|
|
23
26
|
searchValue?: string;
|
|
24
27
|
displayValue?: string;
|
|
28
|
+
inputTestId?: string;
|
|
29
|
+
inputRef?: React.Ref<HTMLInputElement>;
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
export function Autocomplete({
|
|
@@ -29,6 +34,9 @@ export function Autocomplete({
|
|
|
29
34
|
value,
|
|
30
35
|
onValueChange,
|
|
31
36
|
onBlur: onBlurProp, // Destructure the new onBlur prop
|
|
37
|
+
onCommitUnselectedInput,
|
|
38
|
+
commitUnselectedOnBlur = false,
|
|
39
|
+
committedDisplayValue,
|
|
32
40
|
placeholder = "Type to search...",
|
|
33
41
|
emptyText = "No results found.",
|
|
34
42
|
className,
|
|
@@ -37,10 +45,16 @@ export function Autocomplete({
|
|
|
37
45
|
onSearch,
|
|
38
46
|
searchValue: externalSearchValue,
|
|
39
47
|
displayValue,
|
|
48
|
+
inputTestId,
|
|
49
|
+
inputRef: externalInputRef,
|
|
40
50
|
}: AutocompleteProps) {
|
|
41
51
|
const [open, setOpen] = React.useState(false);
|
|
42
52
|
const [internalSearchValue, setInternalSearchValue] = React.useState("");
|
|
43
53
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
54
|
+
const suppressAutoOpenRef = React.useRef(false);
|
|
55
|
+
const blurCloseRef = React.useRef(false);
|
|
56
|
+
const focusOpenRef = React.useRef(false);
|
|
57
|
+
const selectedValueRef = React.useRef<string | null>(null);
|
|
44
58
|
|
|
45
59
|
const searchValue = externalSearchValue ?? internalSearchValue;
|
|
46
60
|
// Show displayValue when not typing, otherwise show what user is typing
|
|
@@ -48,6 +62,7 @@ export function Autocomplete({
|
|
|
48
62
|
|
|
49
63
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
50
64
|
const value = e.target.value;
|
|
65
|
+
suppressAutoOpenRef.current = false;
|
|
51
66
|
setInternalSearchValue(value);
|
|
52
67
|
onSearch?.(value);
|
|
53
68
|
|
|
@@ -59,22 +74,38 @@ export function Autocomplete({
|
|
|
59
74
|
|
|
60
75
|
// Close popover when options become empty, open when they appear
|
|
61
76
|
React.useEffect(() => {
|
|
77
|
+
if (!displayValue && !value) {
|
|
78
|
+
suppressAutoOpenRef.current = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
if (options.length === 0) {
|
|
63
82
|
setOpen(false);
|
|
83
|
+
} else if (suppressAutoOpenRef.current) {
|
|
84
|
+
return;
|
|
64
85
|
} else if (document.activeElement === inputRef.current && searchValue) {
|
|
65
86
|
setOpen(true);
|
|
66
87
|
}
|
|
67
|
-
}, [options.length, searchValue]);
|
|
88
|
+
}, [displayValue, options.length, searchValue, value]);
|
|
68
89
|
|
|
69
90
|
const handleSelect = (selectedValue: string) => {
|
|
91
|
+
selectedValueRef.current = selectedValue;
|
|
92
|
+
suppressAutoOpenRef.current = true;
|
|
70
93
|
onValueChange?.(selectedValue);
|
|
71
94
|
setOpen(false);
|
|
72
95
|
};
|
|
73
96
|
|
|
74
97
|
const handleInputFocus = () => {
|
|
98
|
+
if (!displayValue) {
|
|
99
|
+
suppressAutoOpenRef.current = false;
|
|
100
|
+
}
|
|
101
|
+
if (suppressAutoOpenRef.current) return;
|
|
75
102
|
// Only open popover on focus if there's no displayValue (no customer selected)
|
|
76
103
|
if (!displayValue && options.length > 0) {
|
|
104
|
+
focusOpenRef.current = true;
|
|
77
105
|
setOpen(true);
|
|
106
|
+
requestAnimationFrame(() => {
|
|
107
|
+
focusOpenRef.current = false;
|
|
108
|
+
});
|
|
78
109
|
}
|
|
79
110
|
};
|
|
80
111
|
|
|
@@ -84,8 +115,30 @@ export function Autocomplete({
|
|
|
84
115
|
if (relatedTarget?.closest('[role="dialog"]')) {
|
|
85
116
|
return;
|
|
86
117
|
}
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
|
|
119
|
+
const typedValue = searchValue?.trim();
|
|
120
|
+
const shouldCommitTypedValue =
|
|
121
|
+
!!typedValue &&
|
|
122
|
+
typedValue !== displayValue &&
|
|
123
|
+
selectedValueRef.current == null &&
|
|
124
|
+
commitUnselectedOnBlur &&
|
|
125
|
+
!!onCommitUnselectedInput;
|
|
126
|
+
|
|
127
|
+
if (shouldCommitTypedValue) {
|
|
128
|
+
onCommitUnselectedInput(typedValue);
|
|
129
|
+
} else if (selectedValueRef.current == null) {
|
|
130
|
+
const restoredValue = committedDisplayValue ?? displayValue ?? "";
|
|
131
|
+
setInternalSearchValue("");
|
|
132
|
+
onSearch?.(restoredValue);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
blurCloseRef.current = true;
|
|
136
|
+
suppressAutoOpenRef.current = false;
|
|
137
|
+
setOpen(false);
|
|
138
|
+
requestAnimationFrame(() => {
|
|
139
|
+
blurCloseRef.current = false;
|
|
140
|
+
selectedValueRef.current = null;
|
|
141
|
+
});
|
|
89
142
|
|
|
90
143
|
onBlurProp?.(e); // Call the passed onBlur prop after internal logic
|
|
91
144
|
};
|
|
@@ -98,8 +151,10 @@ export function Autocomplete({
|
|
|
98
151
|
|
|
99
152
|
// Handle popover open/close - prevent closing when input is focused
|
|
100
153
|
const handleOpenChange = (newOpen: boolean) => {
|
|
101
|
-
if (!newOpen &&
|
|
102
|
-
|
|
154
|
+
if (!newOpen && focusOpenRef.current) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (!newOpen && document.activeElement === inputRef.current && !blurCloseRef.current) {
|
|
103
158
|
return;
|
|
104
159
|
}
|
|
105
160
|
setOpen(newOpen);
|
|
@@ -108,7 +163,14 @@ export function Autocomplete({
|
|
|
108
163
|
return (
|
|
109
164
|
<Popover.Root open={open} onOpenChange={handleOpenChange}>
|
|
110
165
|
<Input
|
|
111
|
-
ref={
|
|
166
|
+
ref={(node) => {
|
|
167
|
+
inputRef.current = node;
|
|
168
|
+
if (typeof externalInputRef === "function") {
|
|
169
|
+
externalInputRef(node);
|
|
170
|
+
} else if (externalInputRef) {
|
|
171
|
+
(externalInputRef as React.MutableRefObject<HTMLInputElement | null>).current = node;
|
|
172
|
+
}
|
|
173
|
+
}}
|
|
112
174
|
value={inputValue}
|
|
113
175
|
onChange={handleInputChange}
|
|
114
176
|
onFocus={handleInputFocus}
|
|
@@ -118,6 +180,7 @@ export function Autocomplete({
|
|
|
118
180
|
className={className}
|
|
119
181
|
disabled={disabled}
|
|
120
182
|
autoComplete="off"
|
|
183
|
+
data-testid={inputTestId}
|
|
121
184
|
/>
|
|
122
185
|
<Popover.Portal>
|
|
123
186
|
<Popover.Positioner anchor={inputRef} align="start" sideOffset={4} className="isolate z-50">
|