@spaceinvoices/react-ui 0.1.1
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/LICENSE +21 -0
- package/README.md +340 -0
- package/cli/dist/index.js +922 -0
- package/package.json +87 -0
- package/registry.json +600 -0
- package/spaceinvoices.schema.json +47 -0
- package/src/app.tsx +25 -0
- package/src/common/autocomplete.tsx +135 -0
- package/src/components/activities/activity-timeline.tsx +160 -0
- package/src/components/activities/index.ts +1 -0
- package/src/components/activities/locales/de.ts +30 -0
- package/src/components/activities/locales/sl.ts +30 -0
- package/src/components/advance-invoices/advance-invoices.hooks.ts +75 -0
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +702 -0
- package/src/components/advance-invoices/create/locales/de.ts +29 -0
- package/src/components/advance-invoices/create/locales/sl.ts +25 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +74 -0
- package/src/components/advance-invoices/index.ts +5 -0
- package/src/components/advance-invoices/list/index.ts +3 -0
- package/src/components/advance-invoices/list/list-row-actions.tsx +119 -0
- package/src/components/advance-invoices/list/list-table.tsx +178 -0
- package/src/components/advance-invoices/list/locales/de.ts +32 -0
- package/src/components/advance-invoices/list/locales/sl.ts +32 -0
- package/src/components/advance-invoices/list/use-advance-invoice-download.ts +63 -0
- package/src/components/button-loader.tsx +11 -0
- package/src/components/combobox.tsx +96 -0
- package/src/components/company-registry/company-registry-autocomplete.tsx +151 -0
- package/src/components/company-registry/company-registry.hooks.ts +67 -0
- package/src/components/company-registry/index.ts +7 -0
- package/src/components/credit-notes/create/create-credit-note-form.tsx +332 -0
- package/src/components/credit-notes/create/index.ts +1 -0
- package/src/components/credit-notes/create/locales/de.ts +69 -0
- package/src/components/credit-notes/create/locales/sl.ts +67 -0
- package/src/components/credit-notes/credit-notes.hooks.ts +22 -0
- package/src/components/credit-notes/index.ts +10 -0
- package/src/components/credit-notes/list/index.ts +3 -0
- package/src/components/credit-notes/list/list-row-actions.tsx +116 -0
- package/src/components/credit-notes/list/list-table.tsx +183 -0
- package/src/components/credit-notes/list/locales/de.ts +33 -0
- package/src/components/credit-notes/list/locales/sl.ts +33 -0
- package/src/components/credit-notes/list/use-credit-note-download.ts +65 -0
- package/src/components/customers/create-customer-form/create-customer-form.tsx +134 -0
- package/src/components/customers/create-customer-form/locales/de.ts +20 -0
- package/src/components/customers/create-customer-form/locales/sl.ts +20 -0
- package/src/components/customers/customer-autocomplete.tsx +173 -0
- package/src/components/customers/customer-combobox.tsx +130 -0
- package/src/components/customers/customer-list-table/customer-list-row-actions.tsx +48 -0
- package/src/components/customers/customer-list-table/customer-list-table.tsx +124 -0
- package/src/components/customers/customer-list-table/index.ts +2 -0
- package/src/components/customers/customer-list-table/locales/de.ts +16 -0
- package/src/components/customers/customer-list-table/locales/sl.ts +16 -0
- package/src/components/customers/customers.hooks.test.ts +348 -0
- package/src/components/customers/customers.hooks.ts +57 -0
- package/src/components/customers/index.ts +5 -0
- package/src/components/dashboard/chart-empty-state.tsx +29 -0
- package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +80 -0
- package/src/components/dashboard/collection-rate-card/index.ts +4 -0
- package/src/components/dashboard/collection-rate-card/locales/sl.ts +3 -0
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +74 -0
- package/src/components/dashboard/index.ts +54 -0
- package/src/components/dashboard/invoice-status-chart/index.ts +4 -0
- package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +130 -0
- package/src/components/dashboard/invoice-status-chart/locales/sl.ts +9 -0
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +105 -0
- package/src/components/dashboard/loading-card.tsx +19 -0
- package/src/components/dashboard/payment-methods-chart/index.ts +4 -0
- package/src/components/dashboard/payment-methods-chart/locales/sl.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +152 -0
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +50 -0
- package/src/components/dashboard/payment-trend-chart/index.ts +4 -0
- package/src/components/dashboard/payment-trend-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +137 -0
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +92 -0
- package/src/components/dashboard/revenue-card.tsx +49 -0
- package/src/components/dashboard/revenue-trend-chart/index.ts +4 -0
- package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +137 -0
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +93 -0
- package/src/components/dashboard/shared/index.ts +5 -0
- package/src/components/dashboard/shared/use-revenue-data.ts +160 -0
- package/src/components/dashboard/shared/use-stats-counts.ts +89 -0
- package/src/components/dashboard/shared/use-stats-query.ts +38 -0
- package/src/components/dashboard/stat-card.tsx +41 -0
- package/src/components/dashboard/tax-collected-card/index.ts +2 -0
- package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +77 -0
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +145 -0
- package/src/components/dashboard/top-customers-chart/index.ts +4 -0
- package/src/components/dashboard/top-customers-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +130 -0
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +72 -0
- package/src/components/documents/create/document-add-item-form.tsx +379 -0
- package/src/components/documents/create/document-add-item-tax-rate-field.tsx +120 -0
- package/src/components/documents/create/document-details-section.tsx +597 -0
- package/src/components/documents/create/document-items-section.tsx +133 -0
- package/src/components/documents/create/document-recipient-section.tsx +101 -0
- package/src/components/documents/create/form-types.ts +36 -0
- package/src/components/documents/create/index.ts +9 -0
- package/src/components/documents/create/live-preview.tsx +235 -0
- package/src/components/documents/create/mark-as-paid-section.tsx +82 -0
- package/src/components/documents/create/prepare-document-submission.test.ts +132 -0
- package/src/components/documents/create/prepare-document-submission.ts +187 -0
- package/src/components/documents/create/prepare-preview-data.test.ts +155 -0
- package/src/components/documents/create/prepare-preview-data.ts +16 -0
- package/src/components/documents/create/smart-code-insert-button.tsx +139 -0
- package/src/components/documents/create/use-document-customer-form.ts +161 -0
- package/src/components/documents/document-preview.tsx +13 -0
- package/src/components/documents/documents.hooks.ts +146 -0
- package/src/components/documents/index.ts +23 -0
- package/src/components/documents/shared/document-preview-display.tsx +172 -0
- package/src/components/documents/shared/index.ts +3 -0
- package/src/components/documents/shared/scaled-document-preview.tsx +70 -0
- package/src/components/documents/shared/use-a4-scaling.ts +62 -0
- package/src/components/documents/types.ts +61 -0
- package/src/components/documents/view/document-actions-bar.tsx +328 -0
- package/src/components/documents/view/document-details-card.tsx +179 -0
- package/src/components/documents/view/document-payments-list.tsx +256 -0
- package/src/components/documents/view/index.ts +4 -0
- package/src/components/documents/view/locales/de.ts +85 -0
- package/src/components/documents/view/locales/sl.ts +84 -0
- package/src/components/documents/view/use-document-download.ts +125 -0
- package/src/components/entities/create-entity-form.tsx +105 -0
- package/src/components/entities/entities.hooks.ts +50 -0
- package/src/components/entities/entity-settings-form/email-template-variables-info.tsx +103 -0
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +1326 -0
- package/src/components/entities/entity-settings-form/image-upload-with-crop.tsx +222 -0
- package/src/components/entities/entity-settings-form/index.ts +2 -0
- package/src/components/entities/entity-settings-form/input-with-preview.tsx +190 -0
- package/src/components/entities/entity-settings-form/locales/de.ts +192 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +188 -0
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +410 -0
- package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +320 -0
- package/src/components/entities/furs-settings-form/index.ts +3 -0
- package/src/components/entities/furs-settings-form/locales/de.ts +233 -0
- package/src/components/entities/furs-settings-form/locales/en.ts +194 -0
- package/src/components/entities/furs-settings-form/locales/sl.ts +196 -0
- package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +242 -0
- package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +139 -0
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +252 -0
- package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +370 -0
- package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +420 -0
- package/src/components/entities/keys.ts +2 -0
- package/src/components/entities/settings/branding-settings-form.tsx +274 -0
- package/src/components/entities/settings/company-settings-form.tsx +256 -0
- package/src/components/entities/settings/defaults-settings-form.tsx +501 -0
- package/src/components/entities/settings/email-settings-form.tsx +288 -0
- package/src/components/entities/settings/eslog-settings-form.tsx +113 -0
- package/src/components/entities/settings/index.ts +8 -0
- package/src/components/entities/settings/number-format-settings-form.tsx +244 -0
- package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +164 -0
- package/src/components/entities/settings/pdf-template-selector/index.ts +2 -0
- package/src/components/entities/settings/pdf-template-selector/locales/de.ts +18 -0
- package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +18 -0
- package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +49 -0
- package/src/components/entities/settings/settings-footer.tsx +16 -0
- package/src/components/entities/settings/tax-rules-settings-form.tsx +346 -0
- package/src/components/estimates/create/create-estimate-form.tsx +384 -0
- package/src/components/estimates/create/locales/de.ts +64 -0
- package/src/components/estimates/create/locales/sl.ts +63 -0
- package/src/components/estimates/create/prepare-estimate-submission.ts +39 -0
- package/src/components/estimates/create/use-estimate-customer-form.ts +5 -0
- package/src/components/estimates/estimates.hooks.ts +15 -0
- package/src/components/estimates/index.ts +6 -0
- package/src/components/estimates/list/index.ts +3 -0
- package/src/components/estimates/list/list-row-actions.tsx +103 -0
- package/src/components/estimates/list/list-table.tsx +171 -0
- package/src/components/estimates/list/locales/de.ts +26 -0
- package/src/components/estimates/list/locales/sl.ts +26 -0
- package/src/components/estimates/list/use-estimate-download.ts +63 -0
- package/src/components/export/document-export-form.tsx +288 -0
- package/src/components/export/index.ts +2 -0
- package/src/components/form/form-input.tsx +89 -0
- package/src/components/form/index.ts +1 -0
- package/src/components/invoices/create/create-invoice-form.tsx +852 -0
- package/src/components/invoices/create/eslog-validation.test.ts +242 -0
- package/src/components/invoices/create/eslog-validation.ts +208 -0
- package/src/components/invoices/create/locales/de.ts +118 -0
- package/src/components/invoices/create/locales/sl.ts +114 -0
- package/src/components/invoices/create/prepare-invoice-submission.test.ts +777 -0
- package/src/components/invoices/create/prepare-invoice-submission.ts +79 -0
- package/src/components/invoices/create/use-invoice-customer-form.ts +5 -0
- package/src/components/invoices/index.ts +9 -0
- package/src/components/invoices/invoices-furs.hooks.ts +28 -0
- package/src/components/invoices/invoices.hooks.ts +110 -0
- package/src/components/invoices/list/index.ts +3 -0
- package/src/components/invoices/list/list-row-actions.tsx +132 -0
- package/src/components/invoices/list/list-table.tsx +165 -0
- package/src/components/invoices/list/locales/de.ts +33 -0
- package/src/components/invoices/list/locales/sl.ts +33 -0
- package/src/components/invoices/list/use-invoice-download.ts +62 -0
- package/src/components/invoices/send-email-dialog/index.ts +1 -0
- package/src/components/invoices/send-email-dialog/locales/de.ts +18 -0
- package/src/components/invoices/send-email-dialog/locales/sl.ts +17 -0
- package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +289 -0
- package/src/components/invoices/send-email-dialog.tsx +2 -0
- package/src/components/invoices/shared/index.ts +2 -0
- package/src/components/invoices/shared/scaled-document-preview.tsx +32 -0
- package/src/components/invoices/shared/use-a4-scaling.tsx +39 -0
- package/src/components/invoices/view/eslog-info-display.tsx +160 -0
- package/src/components/invoices/view/furs-info-display.tsx +213 -0
- package/src/components/items/create-item-form/create-item-form.tsx +155 -0
- package/src/components/items/create-item-form/locales/de.ts +14 -0
- package/src/components/items/create-item-form/locales/en.ts +9 -0
- package/src/components/items/create-item-form/locales/sl.ts +14 -0
- package/src/components/items/item-combobox.tsx +147 -0
- package/src/components/items/item-list-table/item-list-header.tsx +33 -0
- package/src/components/items/item-list-table/item-list-row-actions.tsx +48 -0
- package/src/components/items/item-list-table/item-list-row.tsx +32 -0
- package/src/components/items/item-list-table/item-list-table.tsx +76 -0
- package/src/components/items/item-list-table/locales/de.ts +10 -0
- package/src/components/items/item-list-table/locales/en.ts +10 -0
- package/src/components/items/item-list-table/locales/sl.ts +10 -0
- package/src/components/items/items.hooks.ts +63 -0
- package/src/components/loading-spinner.tsx +24 -0
- package/src/components/payments/create-payment-form/create-payment-form.tsx +222 -0
- package/src/components/payments/create-payment-form/locales/de.ts +20 -0
- package/src/components/payments/create-payment-form/locales/sl.ts +20 -0
- package/src/components/payments/edit-payment-form/edit-payment-form.tsx +230 -0
- package/src/components/payments/edit-payment-form/index.ts +1 -0
- package/src/components/payments/edit-payment-form/locales/de.ts +20 -0
- package/src/components/payments/edit-payment-form/locales/sl.ts +20 -0
- package/src/components/payments/index.ts +4 -0
- package/src/components/payments/list/index.ts +2 -0
- package/src/components/payments/list/list-row-actions.tsx +98 -0
- package/src/components/payments/list/list-table.tsx +186 -0
- package/src/components/payments/list/locales/de.ts +19 -0
- package/src/components/payments/list/locales/sl.ts +19 -0
- package/src/components/payments/payments.hooks.ts +15 -0
- package/src/components/request-logs/index.ts +3 -0
- package/src/components/request-logs/request-log-detail.tsx +242 -0
- package/src/components/request-logs/request-log-list-table.tsx +266 -0
- package/src/components/request-logs/request-logs-page.tsx +10 -0
- package/src/components/table/README.md +410 -0
- package/src/components/table/data-table.tsx +251 -0
- package/src/components/table/date-cell.tsx +35 -0
- package/src/components/table/filter-bar.tsx +114 -0
- package/src/components/table/filter-panel.tsx +407 -0
- package/src/components/table/hooks/use-table-fetch.ts +17 -0
- package/src/components/table/hooks/use-table-query.ts +36 -0
- package/src/components/table/hooks/use-table-state.ts +293 -0
- package/src/components/table/index.ts +35 -0
- package/src/components/table/search-input.tsx +85 -0
- package/src/components/table/sortable-header.tsx +56 -0
- package/src/components/table/table-empty-state.tsx +40 -0
- package/src/components/table/table-no-results.tsx +41 -0
- package/src/components/table/table-pagination.tsx +42 -0
- package/src/components/table/table-skeleton.tsx +54 -0
- package/src/components/table/types.ts +136 -0
- package/src/components/tax-reports/index.ts +1 -0
- package/src/components/tax-reports/kir-export-form.tsx +172 -0
- package/src/components/taxes/create-tax-form/create-tax-form.tsx +112 -0
- package/src/components/taxes/create-tax-form/locales/de.ts +8 -0
- package/src/components/taxes/create-tax-form/locales/en.ts +7 -0
- package/src/components/taxes/create-tax-form/locales/sl.ts +8 -0
- package/src/components/taxes/tax-list-table/locales/de.ts +11 -0
- package/src/components/taxes/tax-list-table/locales/en.ts +10 -0
- package/src/components/taxes/tax-list-table/locales/sl.ts +11 -0
- package/src/components/taxes/tax-list-table/tax-list-header.tsx +29 -0
- package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +43 -0
- package/src/components/taxes/tax-list-table/tax-list-row.tsx +46 -0
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +59 -0
- package/src/components/taxes/taxes.hooks.ts +35 -0
- package/src/components/ui/alert-dialog.tsx +61 -0
- package/src/components/ui/alert.tsx +72 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/breadcrumb.tsx +132 -0
- package/src/components/ui/button.tsx +61 -0
- package/src/components/ui/calendar.tsx +213 -0
- package/src/components/ui/card.tsx +94 -0
- package/src/components/ui/chart.tsx +380 -0
- package/src/components/ui/checkbox.tsx +27 -0
- package/src/components/ui/collapsible.tsx +56 -0
- package/src/components/ui/command.tsx +187 -0
- package/src/components/ui/dialog.tsx +187 -0
- package/src/components/ui/drawer.tsx +123 -0
- package/src/components/ui/dropdown-menu.tsx +291 -0
- package/src/components/ui/form.tsx +166 -0
- package/src/components/ui/input-group.tsx +149 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/label.tsx +18 -0
- package/src/components/ui/loading-spinner.tsx +16 -0
- package/src/components/ui/popover.tsx +108 -0
- package/src/components/ui/radio-group.tsx +37 -0
- package/src/components/ui/select.tsx +200 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +145 -0
- package/src/components/ui/sidebar.tsx +771 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +60 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/sticky-form-footer.tsx +55 -0
- package/src/components/ui/switch.tsx +30 -0
- package/src/components/ui/table.tsx +101 -0
- package/src/components/ui/tabs.tsx +80 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +89 -0
- package/src/components/wl-subscription/index.ts +2 -0
- package/src/components/wl-subscription/locked-feature.tsx +173 -0
- package/src/components/wl-subscription/upgrade-modal.tsx +209 -0
- package/src/frontend.tsx +28 -0
- package/src/generate-schemas.ts +265 -0
- package/src/generated/schemas/advanceinvoice.ts +177 -0
- package/src/generated/schemas/creditnote.ts +187 -0
- package/src/generated/schemas/customer.ts +29 -0
- package/src/generated/schemas/entity.ts +252 -0
- package/src/generated/schemas/estimate.ts +159 -0
- package/src/generated/schemas/furssettings.ts +25 -0
- package/src/generated/schemas/index.ts +24 -0
- package/src/generated/schemas/invoice.ts +167 -0
- package/src/generated/schemas/item.ts +38 -0
- package/src/generated/schemas/payment.ts +44 -0
- package/src/generated/schemas/previewadvanceinvoice_body.ts +354 -0
- package/src/generated/schemas/previewestimate_body.ts +309 -0
- package/src/generated/schemas/registerfursmovablepremise_body.ts +22 -0
- package/src/generated/schemas/registerfursrealestatepremise_body.ts +32 -0
- package/src/generated/schemas/renderdocument_body.ts +594 -0
- package/src/generated/schemas/sendemail_body.ts +26 -0
- package/src/generated/schemas/startpdfexport_body.ts +20 -0
- package/src/generated/schemas/tax.ts +48 -0
- package/src/generated/schemas/uploadfile_body.ts +23 -0
- package/src/generated/schemas/uploadfurscertificate_body.ts +20 -0
- package/src/generated/schemas/userfurssettings.ts +19 -0
- package/src/hooks/create-resource-hooks.test.ts +483 -0
- package/src/hooks/create-resource-hooks.ts +300 -0
- package/src/hooks/use-debounce.ts +12 -0
- package/src/hooks/use-duplicate-document.ts +185 -0
- package/src/hooks/use-media-query.tsx +19 -0
- package/src/hooks/use-mobile.ts +39 -0
- package/src/hooks/use-next-document-number.ts +57 -0
- package/src/hooks/use-resource-mutation.ts +118 -0
- package/src/hooks/use-vies-check.ts +130 -0
- package/src/index.css +11 -0
- package/src/index.html +13 -0
- package/src/index.tsx +12 -0
- package/src/lib/auth.ts +4 -0
- package/src/lib/browser-cookies.ts +70 -0
- package/src/lib/constants.ts +287 -0
- package/src/lib/cookies.ts +36 -0
- package/src/lib/schemas/advance-invoice.ts +43 -0
- package/src/lib/schemas/credit-note.ts +32 -0
- package/src/lib/schemas/estimate.ts +31 -0
- package/src/lib/schemas/index.ts +18 -0
- package/src/lib/schemas/invoice.ts +43 -0
- package/src/lib/schemas/shared.ts +79 -0
- package/src/lib/translation.ts +38 -0
- package/src/lib/utils.ts +6 -0
- package/src/providers/entities-context.tsx +41 -0
- package/src/providers/entities-provider.tsx +201 -0
- package/src/providers/form-footer-context.tsx +72 -0
- package/src/providers/sdk-provider.tsx +164 -0
- package/src/providers/white-label-provider.tsx +91 -0
- package/src/providers/wl-subscription-provider.tsx +277 -0
- package/src/utils/string-helpers.ts +111 -0
|
@@ -0,0 +1,922 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// cli/src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// cli/src/commands/init.ts
|
|
7
|
+
import fs4 from "fs";
|
|
8
|
+
import path4 from "path";
|
|
9
|
+
import prompts from "prompts";
|
|
10
|
+
|
|
11
|
+
// cli/src/utils/config.ts
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
var CONFIG_FILE = "spaceinvoices.json";
|
|
15
|
+
var DEFAULT_CONFIG = {
|
|
16
|
+
$schema: "https://raw.githubusercontent.com/space-invoices/react-ui/main/spaceinvoices.schema.json",
|
|
17
|
+
aliases: {
|
|
18
|
+
components: "@/components/space-invoices",
|
|
19
|
+
ui: "@/components/ui",
|
|
20
|
+
lib: "@/lib",
|
|
21
|
+
hooks: "@/hooks",
|
|
22
|
+
providers: "@/providers"
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function getConfigPath(cwd = process.cwd()) {
|
|
26
|
+
return path.join(cwd, CONFIG_FILE);
|
|
27
|
+
}
|
|
28
|
+
function configExists(cwd = process.cwd()) {
|
|
29
|
+
return fs.existsSync(getConfigPath(cwd));
|
|
30
|
+
}
|
|
31
|
+
function readConfig(cwd = process.cwd()) {
|
|
32
|
+
const configPath = getConfigPath(cwd);
|
|
33
|
+
if (!fs.existsSync(configPath)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
38
|
+
return JSON.parse(content);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function writeConfig(config, cwd = process.cwd()) {
|
|
44
|
+
const configPath = getConfigPath(cwd);
|
|
45
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// cli/src/utils/installer.ts
|
|
49
|
+
import { spawn } from "child_process";
|
|
50
|
+
import fs2 from "fs";
|
|
51
|
+
import path2 from "path";
|
|
52
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
53
|
+
if (fs2.existsSync(path2.join(cwd, "bun.lockb")) || fs2.existsSync(path2.join(cwd, "bun.lock"))) {
|
|
54
|
+
return "bun";
|
|
55
|
+
}
|
|
56
|
+
if (fs2.existsSync(path2.join(cwd, "pnpm-lock.yaml"))) {
|
|
57
|
+
return "pnpm";
|
|
58
|
+
}
|
|
59
|
+
if (fs2.existsSync(path2.join(cwd, "yarn.lock"))) {
|
|
60
|
+
return "yarn";
|
|
61
|
+
}
|
|
62
|
+
if (fs2.existsSync(path2.join(cwd, "package-lock.json"))) {
|
|
63
|
+
return "npm";
|
|
64
|
+
}
|
|
65
|
+
const packageJsonPath = path2.join(cwd, "package.json");
|
|
66
|
+
if (fs2.existsSync(packageJsonPath)) {
|
|
67
|
+
try {
|
|
68
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
69
|
+
if (packageJson.packageManager) {
|
|
70
|
+
if (packageJson.packageManager.startsWith("bun")) return "bun";
|
|
71
|
+
if (packageJson.packageManager.startsWith("pnpm")) return "pnpm";
|
|
72
|
+
if (packageJson.packageManager.startsWith("yarn")) return "yarn";
|
|
73
|
+
if (packageJson.packageManager.startsWith("npm")) return "npm";
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return "npm";
|
|
79
|
+
}
|
|
80
|
+
function getInstallCommand(pm, packages, options = {}) {
|
|
81
|
+
const devFlag = options.dev ? " -D" : "";
|
|
82
|
+
switch (pm) {
|
|
83
|
+
case "bun":
|
|
84
|
+
return `bun add${devFlag} ${packages.join(" ")}`;
|
|
85
|
+
case "pnpm":
|
|
86
|
+
return `pnpm add${devFlag} ${packages.join(" ")}`;
|
|
87
|
+
case "yarn":
|
|
88
|
+
return `yarn add${devFlag} ${packages.join(" ")}`;
|
|
89
|
+
case "npm":
|
|
90
|
+
default:
|
|
91
|
+
return `npm install${options.dev ? " --save-dev" : ""} ${packages.join(" ")}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function installPackages(packages, options = {}) {
|
|
95
|
+
if (packages.length === 0) return;
|
|
96
|
+
const cwd = options.cwd ?? process.cwd();
|
|
97
|
+
const pm = detectPackageManager(cwd);
|
|
98
|
+
const command = getInstallCommand(pm, packages, { dev: options.dev });
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
const [cmd, ...args] = command.split(" ");
|
|
101
|
+
const child = spawn(cmd, args, {
|
|
102
|
+
cwd,
|
|
103
|
+
stdio: "inherit",
|
|
104
|
+
shell: true
|
|
105
|
+
});
|
|
106
|
+
child.on("close", (code) => {
|
|
107
|
+
if (code === 0) {
|
|
108
|
+
resolve();
|
|
109
|
+
} else {
|
|
110
|
+
reject(new Error(`Package installation failed with code ${code}`));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
child.on("error", (err) => {
|
|
114
|
+
reject(err);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function getInstalledPackages(cwd = process.cwd()) {
|
|
119
|
+
const packageJsonPath = path2.join(cwd, "package.json");
|
|
120
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
121
|
+
return /* @__PURE__ */ new Set();
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
125
|
+
const deps = /* @__PURE__ */ new Set();
|
|
126
|
+
if (packageJson.dependencies) {
|
|
127
|
+
for (const dep of Object.keys(packageJson.dependencies)) {
|
|
128
|
+
deps.add(dep);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (packageJson.devDependencies) {
|
|
132
|
+
for (const dep of Object.keys(packageJson.devDependencies)) {
|
|
133
|
+
deps.add(dep);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return deps;
|
|
137
|
+
} catch {
|
|
138
|
+
return /* @__PURE__ */ new Set();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function filterNewPackages(packages, cwd = process.cwd()) {
|
|
142
|
+
const installed = getInstalledPackages(cwd);
|
|
143
|
+
return packages.filter((pkg) => !installed.has(pkg));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// cli/src/utils/logger.ts
|
|
147
|
+
import pc from "picocolors";
|
|
148
|
+
var logger = {
|
|
149
|
+
info: (msg) => console.log(pc.blue("info"), msg),
|
|
150
|
+
success: (msg) => console.log(pc.green("success"), msg),
|
|
151
|
+
warn: (msg) => console.log(pc.yellow("warn"), msg),
|
|
152
|
+
error: (msg) => console.log(pc.red("error"), msg),
|
|
153
|
+
log: (msg) => console.log(msg),
|
|
154
|
+
break: () => console.log("")
|
|
155
|
+
};
|
|
156
|
+
function spinner(text) {
|
|
157
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
158
|
+
let i = 0;
|
|
159
|
+
let intervalId = null;
|
|
160
|
+
return {
|
|
161
|
+
start: () => {
|
|
162
|
+
process.stdout.write(`\r${pc.cyan(frames[0])} ${text}`);
|
|
163
|
+
intervalId = setInterval(() => {
|
|
164
|
+
i = (i + 1) % frames.length;
|
|
165
|
+
process.stdout.write(`\r${pc.cyan(frames[i])} ${text}`);
|
|
166
|
+
}, 80);
|
|
167
|
+
},
|
|
168
|
+
stop: (finalText) => {
|
|
169
|
+
if (intervalId) {
|
|
170
|
+
clearInterval(intervalId);
|
|
171
|
+
intervalId = null;
|
|
172
|
+
}
|
|
173
|
+
process.stdout.write(`\r${" ".repeat(text.length + 4)}\r`);
|
|
174
|
+
if (finalText) {
|
|
175
|
+
console.log(finalText);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
succeed: (msg) => {
|
|
179
|
+
if (intervalId) {
|
|
180
|
+
clearInterval(intervalId);
|
|
181
|
+
intervalId = null;
|
|
182
|
+
}
|
|
183
|
+
process.stdout.write(`\r${" ".repeat(text.length + 4)}\r`);
|
|
184
|
+
console.log(`${pc.green("\u2713")} ${msg || text}`);
|
|
185
|
+
},
|
|
186
|
+
fail: (msg) => {
|
|
187
|
+
if (intervalId) {
|
|
188
|
+
clearInterval(intervalId);
|
|
189
|
+
intervalId = null;
|
|
190
|
+
}
|
|
191
|
+
process.stdout.write(`\r${" ".repeat(text.length + 4)}\r`);
|
|
192
|
+
console.log(`${pc.red("\u2717")} ${msg || text}`);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function highlight(text) {
|
|
197
|
+
return pc.cyan(text);
|
|
198
|
+
}
|
|
199
|
+
function dim(text) {
|
|
200
|
+
return pc.dim(text);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// cli/src/utils/registry.ts
|
|
204
|
+
import fs3 from "fs";
|
|
205
|
+
import path3 from "path";
|
|
206
|
+
var REGISTRY_BASE_URL = "https://raw.githubusercontent.com/space-invoices/react-ui/main";
|
|
207
|
+
var localBasePath = null;
|
|
208
|
+
function setLocalBasePath(basePath) {
|
|
209
|
+
localBasePath = basePath;
|
|
210
|
+
}
|
|
211
|
+
var cachedRegistry = null;
|
|
212
|
+
async function fetchRegistry() {
|
|
213
|
+
if (cachedRegistry) {
|
|
214
|
+
return cachedRegistry;
|
|
215
|
+
}
|
|
216
|
+
if (localBasePath) {
|
|
217
|
+
const registryPath = path3.join(localBasePath, "registry.json");
|
|
218
|
+
const content = fs3.readFileSync(registryPath, "utf-8");
|
|
219
|
+
cachedRegistry = JSON.parse(content);
|
|
220
|
+
return cachedRegistry;
|
|
221
|
+
}
|
|
222
|
+
const response = await fetch(`${REGISTRY_BASE_URL}/registry.json`);
|
|
223
|
+
if (!response.ok) {
|
|
224
|
+
throw new Error(`Failed to fetch registry: ${response.statusText}`);
|
|
225
|
+
}
|
|
226
|
+
cachedRegistry = await response.json();
|
|
227
|
+
return cachedRegistry;
|
|
228
|
+
}
|
|
229
|
+
async function fetchFile(filePath) {
|
|
230
|
+
if (localBasePath) {
|
|
231
|
+
const fullPath = path3.join(localBasePath, "src", filePath);
|
|
232
|
+
return fs3.readFileSync(fullPath, "utf-8");
|
|
233
|
+
}
|
|
234
|
+
const url = `${REGISTRY_BASE_URL}/src/${filePath}`;
|
|
235
|
+
const response = await fetch(url);
|
|
236
|
+
if (!response.ok) {
|
|
237
|
+
throw new Error(`Failed to fetch file ${filePath}: ${response.statusText}`);
|
|
238
|
+
}
|
|
239
|
+
return response.text();
|
|
240
|
+
}
|
|
241
|
+
function getComponent(registry, name) {
|
|
242
|
+
return registry.components[name] ?? null;
|
|
243
|
+
}
|
|
244
|
+
function getProvider(registry, name) {
|
|
245
|
+
const providerName = name.replace(/^providers\//, "");
|
|
246
|
+
return registry.providers[providerName] ?? null;
|
|
247
|
+
}
|
|
248
|
+
function getUtil(registry, name) {
|
|
249
|
+
const utilName = name.replace(/^utils\//, "");
|
|
250
|
+
return registry.utils[utilName] ?? null;
|
|
251
|
+
}
|
|
252
|
+
function listComponents(registry) {
|
|
253
|
+
return Object.keys(registry.components);
|
|
254
|
+
}
|
|
255
|
+
function getComponentsByCategory(registry) {
|
|
256
|
+
const result = {};
|
|
257
|
+
for (const [key, component] of Object.entries(registry.components)) {
|
|
258
|
+
const category = component.category;
|
|
259
|
+
if (!result[category]) {
|
|
260
|
+
result[category] = {
|
|
261
|
+
name: registry.categories[category]?.name ?? category,
|
|
262
|
+
components: []
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
result[category].components.push({ key, name: component.name });
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// cli/src/utils/transformer.ts
|
|
271
|
+
function transformImports(source, config) {
|
|
272
|
+
let result = source;
|
|
273
|
+
const replacements = [
|
|
274
|
+
// UI components: @/ui/components/ui/ -> config.aliases.ui/
|
|
275
|
+
[/@\/ui\/components\/ui\//g, `${config.aliases.ui}/`],
|
|
276
|
+
// Feature components: @/ui/components/ -> config.aliases.components/
|
|
277
|
+
[/@\/ui\/components\//g, `${config.aliases.components}/`],
|
|
278
|
+
// Providers: @/ui/providers/ -> config.aliases.providers/
|
|
279
|
+
[/@\/ui\/providers\//g, `${config.aliases.providers}/`],
|
|
280
|
+
// Lib utilities: @/ui/lib/ -> config.aliases.lib/
|
|
281
|
+
[/@\/ui\/lib\//g, `${config.aliases.lib}/`],
|
|
282
|
+
// Hooks: @/ui/hooks/ -> config.aliases.hooks/
|
|
283
|
+
[/@\/ui\/hooks\//g, `${config.aliases.hooks}/`]
|
|
284
|
+
];
|
|
285
|
+
for (const [pattern, replacement] of replacements) {
|
|
286
|
+
result = result.replace(pattern, replacement);
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
function getDestinationPath(sourcePath, config) {
|
|
291
|
+
if (sourcePath.startsWith("components/ui/")) {
|
|
292
|
+
return {
|
|
293
|
+
destPath: sourcePath.replace("components/ui/", ""),
|
|
294
|
+
category: "ui"
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (sourcePath.startsWith("components/")) {
|
|
298
|
+
return {
|
|
299
|
+
destPath: sourcePath.replace("components/", ""),
|
|
300
|
+
category: "components"
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
if (sourcePath.startsWith("providers/")) {
|
|
304
|
+
return {
|
|
305
|
+
destPath: sourcePath.replace("providers/", ""),
|
|
306
|
+
category: "providers"
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
if (sourcePath.startsWith("lib/")) {
|
|
310
|
+
return {
|
|
311
|
+
destPath: sourcePath.replace("lib/", ""),
|
|
312
|
+
category: "lib"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
if (sourcePath.startsWith("hooks/")) {
|
|
316
|
+
return {
|
|
317
|
+
destPath: sourcePath.replace("hooks/", ""),
|
|
318
|
+
category: "hooks"
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
destPath: sourcePath,
|
|
323
|
+
category: "components"
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function getFullDestinationPath(sourcePath, config, basePath) {
|
|
327
|
+
const { destPath, category } = getDestinationPath(sourcePath, config);
|
|
328
|
+
const alias = config.aliases[category];
|
|
329
|
+
let relativePath;
|
|
330
|
+
if (alias.startsWith("@/")) {
|
|
331
|
+
relativePath = alias.slice(2);
|
|
332
|
+
} else {
|
|
333
|
+
relativePath = alias;
|
|
334
|
+
}
|
|
335
|
+
return `${basePath}/src/${relativePath}/${destPath}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// cli/src/commands/init.ts
|
|
339
|
+
var CORE_DEPENDENCIES = ["@spaceinvoices/js-sdk", "@tanstack/react-query"];
|
|
340
|
+
var ESSENTIAL_FILES = [
|
|
341
|
+
"lib/utils.ts",
|
|
342
|
+
"lib/auth.ts",
|
|
343
|
+
"lib/cookies.ts",
|
|
344
|
+
"lib/browser-cookies.ts",
|
|
345
|
+
"lib/translation.ts",
|
|
346
|
+
"providers/sdk-provider.tsx",
|
|
347
|
+
"components/entities/keys.ts"
|
|
348
|
+
];
|
|
349
|
+
async function init(options = {}) {
|
|
350
|
+
const cwd = options.cwd ?? process.cwd();
|
|
351
|
+
logger.break();
|
|
352
|
+
logger.info("Initializing Space Invoices React UI...");
|
|
353
|
+
logger.break();
|
|
354
|
+
if (configExists(cwd) && !options.force) {
|
|
355
|
+
const { overwrite } = await prompts({
|
|
356
|
+
type: "confirm",
|
|
357
|
+
name: "overwrite",
|
|
358
|
+
message: `${CONFIG_FILE} already exists. Overwrite?`,
|
|
359
|
+
initial: false
|
|
360
|
+
});
|
|
361
|
+
if (!overwrite) {
|
|
362
|
+
logger.info("Initialization cancelled.");
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
let config;
|
|
367
|
+
if (options.yes) {
|
|
368
|
+
config = { ...DEFAULT_CONFIG };
|
|
369
|
+
} else {
|
|
370
|
+
const answers = await prompts([
|
|
371
|
+
{
|
|
372
|
+
type: "text",
|
|
373
|
+
name: "components",
|
|
374
|
+
message: "Where should feature components be installed?",
|
|
375
|
+
initial: DEFAULT_CONFIG.aliases.components
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
type: "text",
|
|
379
|
+
name: "ui",
|
|
380
|
+
message: "Where should UI primitives be installed?",
|
|
381
|
+
initial: DEFAULT_CONFIG.aliases.ui
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
type: "text",
|
|
385
|
+
name: "lib",
|
|
386
|
+
message: "Where should lib utilities be installed?",
|
|
387
|
+
initial: DEFAULT_CONFIG.aliases.lib
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
type: "text",
|
|
391
|
+
name: "hooks",
|
|
392
|
+
message: "Where should hooks be installed?",
|
|
393
|
+
initial: DEFAULT_CONFIG.aliases.hooks
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
type: "text",
|
|
397
|
+
name: "providers",
|
|
398
|
+
message: "Where should providers be installed?",
|
|
399
|
+
initial: DEFAULT_CONFIG.aliases.providers
|
|
400
|
+
}
|
|
401
|
+
]);
|
|
402
|
+
if (!answers.components) {
|
|
403
|
+
logger.info("Initialization cancelled.");
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
config = {
|
|
407
|
+
$schema: DEFAULT_CONFIG.$schema,
|
|
408
|
+
aliases: {
|
|
409
|
+
components: answers.components,
|
|
410
|
+
ui: answers.ui,
|
|
411
|
+
lib: answers.lib,
|
|
412
|
+
hooks: answers.hooks,
|
|
413
|
+
providers: answers.providers
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
const configSpinner = spinner("Writing configuration...");
|
|
418
|
+
configSpinner.start();
|
|
419
|
+
try {
|
|
420
|
+
writeConfig(config, cwd);
|
|
421
|
+
configSpinner.succeed(`Created ${highlight(CONFIG_FILE)}`);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
configSpinner.fail(`Failed to create ${CONFIG_FILE}`);
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
426
|
+
const dirSpinner = spinner("Creating directories...");
|
|
427
|
+
dirSpinner.start();
|
|
428
|
+
try {
|
|
429
|
+
const directories = [
|
|
430
|
+
config.aliases.components,
|
|
431
|
+
config.aliases.ui,
|
|
432
|
+
config.aliases.lib,
|
|
433
|
+
config.aliases.hooks,
|
|
434
|
+
config.aliases.providers
|
|
435
|
+
];
|
|
436
|
+
for (const alias of directories) {
|
|
437
|
+
let dirPath;
|
|
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 });
|
|
444
|
+
}
|
|
445
|
+
dirSpinner.succeed("Created directories");
|
|
446
|
+
} catch (error) {
|
|
447
|
+
dirSpinner.fail("Failed to create directories");
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
const filesSpinner = spinner("Copying essential files...");
|
|
451
|
+
filesSpinner.start();
|
|
452
|
+
try {
|
|
453
|
+
for (const filePath of ESSENTIAL_FILES) {
|
|
454
|
+
const content = await fetchFile(filePath);
|
|
455
|
+
const transformed = transformImports(content, config);
|
|
456
|
+
const destPath = getFullDestinationPath(filePath, config, cwd);
|
|
457
|
+
fs4.mkdirSync(path4.dirname(destPath), { recursive: true });
|
|
458
|
+
fs4.writeFileSync(destPath, transformed);
|
|
459
|
+
}
|
|
460
|
+
filesSpinner.succeed(`Copied ${ESSENTIAL_FILES.length} essential files`);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
filesSpinner.fail("Failed to copy essential files");
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
465
|
+
const pm = detectPackageManager(cwd);
|
|
466
|
+
const newDeps = filterNewPackages(CORE_DEPENDENCIES, cwd);
|
|
467
|
+
if (newDeps.length > 0) {
|
|
468
|
+
logger.break();
|
|
469
|
+
logger.info(`Installing dependencies with ${pm}...`);
|
|
470
|
+
logger.break();
|
|
471
|
+
try {
|
|
472
|
+
await installPackages(newDeps, { cwd });
|
|
473
|
+
logger.break();
|
|
474
|
+
logger.success("Installed core dependencies");
|
|
475
|
+
} catch (error) {
|
|
476
|
+
logger.error("Failed to install dependencies. Please install manually:");
|
|
477
|
+
logger.log(` ${newDeps.join(" ")}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
logger.break();
|
|
481
|
+
logger.success("Space Invoices React UI initialized!");
|
|
482
|
+
logger.break();
|
|
483
|
+
logger.info("Next steps:");
|
|
484
|
+
logger.log(` 1. Add components: ${highlight("npx @spaceinvoices/react-ui add customers/create-customer-form")}`);
|
|
485
|
+
logger.log(` 2. Import and use in your app`);
|
|
486
|
+
logger.break();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// cli/src/commands/add.ts
|
|
490
|
+
import fs5 from "fs";
|
|
491
|
+
import path5 from "path";
|
|
492
|
+
import prompts2 from "prompts";
|
|
493
|
+
|
|
494
|
+
// cli/src/utils/resolver.ts
|
|
495
|
+
function resolveDependencies(registry, componentNames) {
|
|
496
|
+
const visited = /* @__PURE__ */ new Set();
|
|
497
|
+
const items = [];
|
|
498
|
+
const allFiles = [];
|
|
499
|
+
const npmDepsSet = /* @__PURE__ */ new Set();
|
|
500
|
+
function resolveComponent(name) {
|
|
501
|
+
const key = `component:${name}`;
|
|
502
|
+
if (visited.has(key)) return;
|
|
503
|
+
visited.add(key);
|
|
504
|
+
const component = getComponent(registry, name);
|
|
505
|
+
if (!component) {
|
|
506
|
+
throw new Error(`Component "${name}" not found in registry`);
|
|
507
|
+
}
|
|
508
|
+
if (component.dependencies) {
|
|
509
|
+
for (const dep of component.dependencies) {
|
|
510
|
+
resolveComponent(dep);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (component.providers) {
|
|
514
|
+
for (const providerName of component.providers) {
|
|
515
|
+
resolveProvider(providerName);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (component.utils) {
|
|
519
|
+
for (const utilName of component.utils) {
|
|
520
|
+
resolveUtil(utilName);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
items.push({
|
|
524
|
+
type: "component",
|
|
525
|
+
key: name,
|
|
526
|
+
name: component.name,
|
|
527
|
+
files: component.files,
|
|
528
|
+
npmDependencies: component.npmDependencies ?? []
|
|
529
|
+
});
|
|
530
|
+
allFiles.push(...component.files);
|
|
531
|
+
if (component.npmDependencies) {
|
|
532
|
+
for (const dep of component.npmDependencies) {
|
|
533
|
+
npmDepsSet.add(dep);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function resolveProvider(name) {
|
|
538
|
+
const providerName = name.replace(/^providers\//, "");
|
|
539
|
+
const key = `provider:${providerName}`;
|
|
540
|
+
if (visited.has(key)) return;
|
|
541
|
+
visited.add(key);
|
|
542
|
+
const provider = getProvider(registry, providerName);
|
|
543
|
+
if (!provider) {
|
|
544
|
+
throw new Error(`Provider "${providerName}" not found in registry`);
|
|
545
|
+
}
|
|
546
|
+
if (provider.dependencies) {
|
|
547
|
+
for (const dep of provider.dependencies) {
|
|
548
|
+
resolveProvider(dep);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
items.push({
|
|
552
|
+
type: "provider",
|
|
553
|
+
key: providerName,
|
|
554
|
+
name: provider.name,
|
|
555
|
+
files: provider.files,
|
|
556
|
+
npmDependencies: provider.npmDependencies ?? []
|
|
557
|
+
});
|
|
558
|
+
allFiles.push(...provider.files);
|
|
559
|
+
if (provider.npmDependencies) {
|
|
560
|
+
for (const dep of provider.npmDependencies) {
|
|
561
|
+
npmDepsSet.add(dep);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function resolveUtil(name) {
|
|
566
|
+
const utilName = name.replace(/^utils\//, "");
|
|
567
|
+
const key = `util:${utilName}`;
|
|
568
|
+
if (visited.has(key)) return;
|
|
569
|
+
visited.add(key);
|
|
570
|
+
const util = getUtil(registry, utilName);
|
|
571
|
+
if (!util) {
|
|
572
|
+
throw new Error(`Utility "${utilName}" not found in registry`);
|
|
573
|
+
}
|
|
574
|
+
if (util.dependencies) {
|
|
575
|
+
for (const dep of util.dependencies) {
|
|
576
|
+
if (dep.startsWith("providers/") || registry.providers[dep]) {
|
|
577
|
+
resolveProvider(dep);
|
|
578
|
+
} else {
|
|
579
|
+
resolveUtil(dep);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
items.push({
|
|
584
|
+
type: "util",
|
|
585
|
+
key: utilName,
|
|
586
|
+
name: util.name,
|
|
587
|
+
files: util.files,
|
|
588
|
+
npmDependencies: util.npmDependencies ?? []
|
|
589
|
+
});
|
|
590
|
+
allFiles.push(...util.files);
|
|
591
|
+
if (util.npmDependencies) {
|
|
592
|
+
for (const dep of util.npmDependencies) {
|
|
593
|
+
npmDepsSet.add(dep);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
for (const name of componentNames) {
|
|
598
|
+
resolveComponent(name);
|
|
599
|
+
}
|
|
600
|
+
const uniqueFiles = [...new Set(allFiles)];
|
|
601
|
+
return {
|
|
602
|
+
items,
|
|
603
|
+
allFiles: uniqueFiles,
|
|
604
|
+
allNpmDependencies: [...npmDepsSet]
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
function getInstallSummary(resolved) {
|
|
608
|
+
return {
|
|
609
|
+
components: resolved.items.filter((i) => i.type === "component").map((i) => i.name),
|
|
610
|
+
providers: resolved.items.filter((i) => i.type === "provider").map((i) => i.name),
|
|
611
|
+
utils: resolved.items.filter((i) => i.type === "util").map((i) => i.name),
|
|
612
|
+
npmPackages: resolved.allNpmDependencies,
|
|
613
|
+
fileCount: resolved.allFiles.length
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// cli/src/commands/add.ts
|
|
618
|
+
async function add(componentNames, options = {}) {
|
|
619
|
+
const cwd = options.cwd ?? process.cwd();
|
|
620
|
+
if (!configExists(cwd)) {
|
|
621
|
+
logger.error(
|
|
622
|
+
"No spaceinvoices.json found. Run `npx @spaceinvoices/react-ui init` first."
|
|
623
|
+
);
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
const config = readConfig(cwd);
|
|
627
|
+
if (!config) {
|
|
628
|
+
logger.error("Failed to read spaceinvoices.json");
|
|
629
|
+
process.exit(1);
|
|
630
|
+
}
|
|
631
|
+
const registrySpinner = spinner("Fetching component registry...");
|
|
632
|
+
registrySpinner.start();
|
|
633
|
+
let registry;
|
|
634
|
+
try {
|
|
635
|
+
registry = await fetchRegistry();
|
|
636
|
+
registrySpinner.succeed("Fetched component registry");
|
|
637
|
+
} catch (error) {
|
|
638
|
+
registrySpinner.fail("Failed to fetch registry");
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
if (options.all) {
|
|
642
|
+
componentNames = listComponents(registry);
|
|
643
|
+
}
|
|
644
|
+
if (componentNames.length === 0) {
|
|
645
|
+
const components = await selectComponents(registry);
|
|
646
|
+
if (components.length === 0) {
|
|
647
|
+
logger.info("No components selected.");
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
componentNames = components;
|
|
651
|
+
}
|
|
652
|
+
const availableComponents = listComponents(registry);
|
|
653
|
+
for (const name of componentNames) {
|
|
654
|
+
if (!availableComponents.includes(name)) {
|
|
655
|
+
logger.error(`Component "${name}" not found in registry.`);
|
|
656
|
+
logger.info("Available components:");
|
|
657
|
+
for (const comp of availableComponents) {
|
|
658
|
+
logger.log(` - ${comp}`);
|
|
659
|
+
}
|
|
660
|
+
process.exit(1);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
logger.break();
|
|
664
|
+
const resolveSpinner = spinner("Resolving dependencies...");
|
|
665
|
+
resolveSpinner.start();
|
|
666
|
+
let resolved;
|
|
667
|
+
try {
|
|
668
|
+
resolved = resolveDependencies(registry, componentNames);
|
|
669
|
+
const summary2 = getInstallSummary(resolved);
|
|
670
|
+
resolveSpinner.succeed(
|
|
671
|
+
`Resolved ${summary2.fileCount} files with ${summary2.npmPackages.length} npm packages`
|
|
672
|
+
);
|
|
673
|
+
} catch (error) {
|
|
674
|
+
resolveSpinner.fail("Failed to resolve dependencies");
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
const summary = getInstallSummary(resolved);
|
|
678
|
+
logger.break();
|
|
679
|
+
logger.info("The following will be installed:");
|
|
680
|
+
logger.break();
|
|
681
|
+
if (summary.components.length > 0) {
|
|
682
|
+
logger.log(` ${highlight("Components:")} ${summary.components.join(", ")}`);
|
|
683
|
+
}
|
|
684
|
+
if (summary.providers.length > 0) {
|
|
685
|
+
logger.log(` ${highlight("Providers:")} ${summary.providers.join(", ")}`);
|
|
686
|
+
}
|
|
687
|
+
if (summary.utils.length > 0) {
|
|
688
|
+
logger.log(` ${highlight("Utilities:")} ${summary.utils.join(", ")}`);
|
|
689
|
+
}
|
|
690
|
+
if (summary.npmPackages.length > 0) {
|
|
691
|
+
logger.log(
|
|
692
|
+
` ${highlight("npm packages:")} ${summary.npmPackages.join(", ")}`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
logger.log(` ${highlight("Files:")} ${summary.fileCount} files`);
|
|
696
|
+
if (!options.yes) {
|
|
697
|
+
logger.break();
|
|
698
|
+
const { proceed } = await prompts2({
|
|
699
|
+
type: "confirm",
|
|
700
|
+
name: "proceed",
|
|
701
|
+
message: "Proceed with installation?",
|
|
702
|
+
initial: true
|
|
703
|
+
});
|
|
704
|
+
if (!proceed) {
|
|
705
|
+
logger.info("Installation cancelled.");
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
logger.break();
|
|
710
|
+
const filesSpinner = spinner("Installing components...");
|
|
711
|
+
filesSpinner.start();
|
|
712
|
+
const existingFiles = [];
|
|
713
|
+
const filesToWrite = [];
|
|
714
|
+
try {
|
|
715
|
+
for (const filePath of resolved.allFiles) {
|
|
716
|
+
const destPath = getFullDestinationPath(filePath, config, cwd);
|
|
717
|
+
if (fs5.existsSync(destPath)) {
|
|
718
|
+
existingFiles.push(destPath);
|
|
719
|
+
}
|
|
720
|
+
const content = await fetchFile(filePath);
|
|
721
|
+
const transformed = transformImports(content, config);
|
|
722
|
+
filesToWrite.push({ path: destPath, content: transformed });
|
|
723
|
+
}
|
|
724
|
+
} catch (error) {
|
|
725
|
+
filesSpinner.fail("Failed to fetch component files");
|
|
726
|
+
throw error;
|
|
727
|
+
}
|
|
728
|
+
if (existingFiles.length > 0 && !options.overwrite) {
|
|
729
|
+
filesSpinner.stop();
|
|
730
|
+
logger.break();
|
|
731
|
+
logger.warn(`The following files already exist:`);
|
|
732
|
+
for (const file of existingFiles) {
|
|
733
|
+
logger.log(` ${dim(file)}`);
|
|
734
|
+
}
|
|
735
|
+
logger.break();
|
|
736
|
+
const { overwrite } = await prompts2({
|
|
737
|
+
type: "confirm",
|
|
738
|
+
name: "overwrite",
|
|
739
|
+
message: "Overwrite existing files?",
|
|
740
|
+
initial: false
|
|
741
|
+
});
|
|
742
|
+
if (!overwrite) {
|
|
743
|
+
const existingSet = new Set(existingFiles);
|
|
744
|
+
const filteredFiles = filesToWrite.filter((f) => !existingSet.has(f.path));
|
|
745
|
+
if (filteredFiles.length === 0) {
|
|
746
|
+
logger.info("No files to install.");
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
filesToWrite.length = 0;
|
|
750
|
+
filesToWrite.push(...filteredFiles);
|
|
751
|
+
}
|
|
752
|
+
filesSpinner.start();
|
|
753
|
+
}
|
|
754
|
+
try {
|
|
755
|
+
for (const { path: filePath, content } of filesToWrite) {
|
|
756
|
+
fs5.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
757
|
+
fs5.writeFileSync(filePath, content);
|
|
758
|
+
}
|
|
759
|
+
filesSpinner.succeed(`Installed ${filesToWrite.length} files`);
|
|
760
|
+
} catch (error) {
|
|
761
|
+
filesSpinner.fail("Failed to write files");
|
|
762
|
+
throw error;
|
|
763
|
+
}
|
|
764
|
+
const pm = detectPackageManager(cwd);
|
|
765
|
+
const newDeps = filterNewPackages(resolved.allNpmDependencies, cwd);
|
|
766
|
+
if (newDeps.length > 0) {
|
|
767
|
+
logger.break();
|
|
768
|
+
logger.info(`Installing npm dependencies with ${pm}...`);
|
|
769
|
+
logger.break();
|
|
770
|
+
try {
|
|
771
|
+
await installPackages(newDeps, { cwd });
|
|
772
|
+
logger.break();
|
|
773
|
+
logger.success(`Installed ${newDeps.length} npm packages`);
|
|
774
|
+
} catch (error) {
|
|
775
|
+
logger.error("Failed to install npm packages. Please install manually:");
|
|
776
|
+
logger.log(` ${newDeps.join(" ")}`);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
logger.break();
|
|
780
|
+
logger.success("Components installed successfully!");
|
|
781
|
+
logger.break();
|
|
782
|
+
}
|
|
783
|
+
async function selectComponents(registry) {
|
|
784
|
+
const byCategory = getComponentsByCategory(registry);
|
|
785
|
+
const choices = [];
|
|
786
|
+
for (const [categoryKey, category] of Object.entries(byCategory)) {
|
|
787
|
+
choices.push({
|
|
788
|
+
title: `\u2500\u2500 ${category.name} \u2500\u2500`,
|
|
789
|
+
value: `__category_${categoryKey}`,
|
|
790
|
+
description: ""
|
|
791
|
+
});
|
|
792
|
+
for (const comp of category.components) {
|
|
793
|
+
choices.push({
|
|
794
|
+
title: ` ${comp.name}`,
|
|
795
|
+
value: comp.key,
|
|
796
|
+
description: comp.key
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
const { selected } = await prompts2({
|
|
801
|
+
type: "multiselect",
|
|
802
|
+
name: "selected",
|
|
803
|
+
message: "Select components to install",
|
|
804
|
+
choices: choices.filter((c) => !c.value.startsWith("__category_")),
|
|
805
|
+
hint: "- Space to select. Return to submit"
|
|
806
|
+
});
|
|
807
|
+
return selected ?? [];
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// cli/src/commands/list.ts
|
|
811
|
+
async function list(options = {}) {
|
|
812
|
+
const registrySpinner = spinner("Fetching component registry...");
|
|
813
|
+
registrySpinner.start();
|
|
814
|
+
try {
|
|
815
|
+
const registry = await fetchRegistry();
|
|
816
|
+
registrySpinner.succeed("Fetched component registry");
|
|
817
|
+
if (options.json) {
|
|
818
|
+
const output = {
|
|
819
|
+
components: Object.entries(registry.components).map(([key, comp]) => ({
|
|
820
|
+
key,
|
|
821
|
+
name: comp.name,
|
|
822
|
+
category: comp.category,
|
|
823
|
+
files: comp.files.length,
|
|
824
|
+
dependencies: comp.dependencies?.length ?? 0
|
|
825
|
+
})),
|
|
826
|
+
providers: Object.entries(registry.providers).map(([key, prov]) => ({
|
|
827
|
+
key,
|
|
828
|
+
name: prov.name,
|
|
829
|
+
files: prov.files.length
|
|
830
|
+
})),
|
|
831
|
+
utils: Object.entries(registry.utils).map(([key, util]) => ({
|
|
832
|
+
key,
|
|
833
|
+
name: util.name,
|
|
834
|
+
files: util.files.length
|
|
835
|
+
}))
|
|
836
|
+
};
|
|
837
|
+
console.log(JSON.stringify(output, null, 2));
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
logger.break();
|
|
841
|
+
logger.info("Available components:");
|
|
842
|
+
logger.break();
|
|
843
|
+
const byCategory = getComponentsByCategory(registry);
|
|
844
|
+
for (const [categoryKey, category] of Object.entries(byCategory)) {
|
|
845
|
+
logger.log(highlight(`${category.name}:`));
|
|
846
|
+
for (const comp of category.components) {
|
|
847
|
+
logger.log(` ${comp.key.padEnd(40)} ${dim(comp.name)}`);
|
|
848
|
+
}
|
|
849
|
+
logger.break();
|
|
850
|
+
}
|
|
851
|
+
logger.log(highlight("Providers:"));
|
|
852
|
+
for (const [key, prov] of Object.entries(registry.providers)) {
|
|
853
|
+
logger.log(` ${key.padEnd(40)} ${dim(prov.name)}`);
|
|
854
|
+
}
|
|
855
|
+
logger.break();
|
|
856
|
+
logger.log(highlight("Utilities:"));
|
|
857
|
+
for (const [key, util] of Object.entries(registry.utils)) {
|
|
858
|
+
logger.log(` ${key.padEnd(40)} ${dim(util.name)}`);
|
|
859
|
+
}
|
|
860
|
+
logger.break();
|
|
861
|
+
logger.info("Usage:");
|
|
862
|
+
logger.log(` npx @spaceinvoices/react-ui add ${dim("<component-name>")}`);
|
|
863
|
+
logger.log(` npx @spaceinvoices/react-ui add ${dim("customers/create-customer-form")}`);
|
|
864
|
+
logger.break();
|
|
865
|
+
} catch (error) {
|
|
866
|
+
registrySpinner.fail("Failed to fetch registry");
|
|
867
|
+
throw error;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// cli/src/index.ts
|
|
872
|
+
var program = new Command();
|
|
873
|
+
program.name("spaceinvoices-ui").description("CLI for adding Space Invoices React UI components to your project").version("0.1.0");
|
|
874
|
+
program.option("--local <path>", "Use local registry from specified path (for development)");
|
|
875
|
+
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
|
+
const globalOpts = program.opts();
|
|
877
|
+
if (globalOpts.local) {
|
|
878
|
+
setLocalBasePath(globalOpts.local);
|
|
879
|
+
}
|
|
880
|
+
try {
|
|
881
|
+
await init({
|
|
882
|
+
cwd: options.cwd,
|
|
883
|
+
yes: options.yes,
|
|
884
|
+
force: options.force
|
|
885
|
+
});
|
|
886
|
+
} catch (error) {
|
|
887
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
program.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Add all available components").option("-o, --overwrite", "Overwrite existing files without asking").option("--cwd <path>", "Working directory (defaults to current directory)").action(async (components, options) => {
|
|
892
|
+
const globalOpts = program.opts();
|
|
893
|
+
if (globalOpts.local) {
|
|
894
|
+
setLocalBasePath(globalOpts.local);
|
|
895
|
+
}
|
|
896
|
+
try {
|
|
897
|
+
await add(components, {
|
|
898
|
+
cwd: options.cwd,
|
|
899
|
+
yes: options.yes,
|
|
900
|
+
all: options.all,
|
|
901
|
+
overwrite: options.overwrite
|
|
902
|
+
});
|
|
903
|
+
} catch (error) {
|
|
904
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
905
|
+
process.exit(1);
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
program.command("list").description("List available components").option("--json", "Output as JSON").action(async (options) => {
|
|
909
|
+
const globalOpts = program.opts();
|
|
910
|
+
if (globalOpts.local) {
|
|
911
|
+
setLocalBasePath(globalOpts.local);
|
|
912
|
+
}
|
|
913
|
+
try {
|
|
914
|
+
await list({
|
|
915
|
+
json: options.json
|
|
916
|
+
});
|
|
917
|
+
} catch (error) {
|
|
918
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
program.parse();
|