@pipe0/react 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +119 -0
- package/README.md +172 -0
- package/dist/components/compound/pipe-catalog/active-filters.d.mts +26 -0
- package/dist/components/compound/pipe-catalog/active-filters.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/active-filters.mjs +47 -0
- package/dist/components/compound/pipe-catalog/active-filters.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/card.d.mts +30 -0
- package/dist/components/compound/pipe-catalog/card.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/card.mjs +77 -0
- package/dist/components/compound/pipe-catalog/card.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/category-filter.d.mts +30 -0
- package/dist/components/compound/pipe-catalog/category-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/category-filter.mjs +56 -0
- package/dist/components/compound/pipe-catalog/category-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/column-filter.d.mts +40 -0
- package/dist/components/compound/pipe-catalog/column-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/column-filter.mjs +66 -0
- package/dist/components/compound/pipe-catalog/column-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/column-filters.d.mts +16 -0
- package/dist/components/compound/pipe-catalog/column-filters.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/column-filters.mjs +21 -0
- package/dist/components/compound/pipe-catalog/column-filters.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/empty.d.mts +22 -0
- package/dist/components/compound/pipe-catalog/empty.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/empty.mjs +31 -0
- package/dist/components/compound/pipe-catalog/empty.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/index.d.mts +13 -0
- package/dist/components/compound/pipe-catalog/index.mjs +15 -0
- package/dist/components/compound/pipe-catalog/input-field-filter.d.mts +22 -0
- package/dist/components/compound/pipe-catalog/input-field-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/input-field-filter.mjs +22 -0
- package/dist/components/compound/pipe-catalog/input-field-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/list.d.mts +34 -0
- package/dist/components/compound/pipe-catalog/list.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/list.mjs +29 -0
- package/dist/components/compound/pipe-catalog/list.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/output-field-filter.d.mts +22 -0
- package/dist/components/compound/pipe-catalog/output-field-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/output-field-filter.mjs +22 -0
- package/dist/components/compound/pipe-catalog/output-field-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/provider-filter.d.mts +22 -0
- package/dist/components/compound/pipe-catalog/provider-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/provider-filter.mjs +29 -0
- package/dist/components/compound/pipe-catalog/provider-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/root.d.mts +47 -0
- package/dist/components/compound/pipe-catalog/root.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/root.mjs +85 -0
- package/dist/components/compound/pipe-catalog/root.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/search-filter.d.mts +24 -0
- package/dist/components/compound/pipe-catalog/search-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/search-filter.mjs +46 -0
- package/dist/components/compound/pipe-catalog/search-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-catalog/tag-filter.d.mts +22 -0
- package/dist/components/compound/pipe-catalog/tag-filter.d.mts.map +1 -0
- package/dist/components/compound/pipe-catalog/tag-filter.mjs +22 -0
- package/dist/components/compound/pipe-catalog/tag-filter.mjs.map +1 -0
- package/dist/components/compound/pipe-form/content.d.mts +18 -0
- package/dist/components/compound/pipe-form/content.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/content.mjs +45 -0
- package/dist/components/compound/pipe-form/content.mjs.map +1 -0
- package/dist/components/compound/pipe-form/field.d.mts +17 -0
- package/dist/components/compound/pipe-form/field.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/field.mjs +21 -0
- package/dist/components/compound/pipe-form/field.mjs.map +1 -0
- package/dist/components/compound/pipe-form/footer.d.mts +14 -0
- package/dist/components/compound/pipe-form/footer.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/footer.mjs +14 -0
- package/dist/components/compound/pipe-form/footer.mjs.map +1 -0
- package/dist/components/compound/pipe-form/group.d.mts +13 -0
- package/dist/components/compound/pipe-form/group.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/group.mjs +17 -0
- package/dist/components/compound/pipe-form/group.mjs.map +1 -0
- package/dist/components/compound/pipe-form/header.d.mts +14 -0
- package/dist/components/compound/pipe-form/header.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/header.mjs +14 -0
- package/dist/components/compound/pipe-form/header.mjs.map +1 -0
- package/dist/components/compound/pipe-form/index.d.mts +9 -0
- package/dist/components/compound/pipe-form/index.mjs +11 -0
- package/dist/components/compound/pipe-form/root.d.mts +56 -0
- package/dist/components/compound/pipe-form/root.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/root.mjs +98 -0
- package/dist/components/compound/pipe-form/root.mjs.map +1 -0
- package/dist/components/compound/pipe-form/section.d.mts +13 -0
- package/dist/components/compound/pipe-form/section.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/section.mjs +17 -0
- package/dist/components/compound/pipe-form/section.mjs.map +1 -0
- package/dist/components/compound/pipe-form/submit-button.d.mts +9 -0
- package/dist/components/compound/pipe-form/submit-button.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/submit-button.mjs +17 -0
- package/dist/components/compound/pipe-form/submit-button.mjs.map +1 -0
- package/dist/components/compound/pipe-form/title.d.mts +16 -0
- package/dist/components/compound/pipe-form/title.d.mts.map +1 -0
- package/dist/components/compound/pipe-form/title.mjs +14 -0
- package/dist/components/compound/pipe-form/title.mjs.map +1 -0
- package/dist/components/compound/search-catalog/active-filters.d.mts +26 -0
- package/dist/components/compound/search-catalog/active-filters.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/active-filters.mjs +46 -0
- package/dist/components/compound/search-catalog/active-filters.mjs.map +1 -0
- package/dist/components/compound/search-catalog/card.d.mts +30 -0
- package/dist/components/compound/search-catalog/card.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/card.mjs +77 -0
- package/dist/components/compound/search-catalog/card.mjs.map +1 -0
- package/dist/components/compound/search-catalog/category-filter.d.mts +29 -0
- package/dist/components/compound/search-catalog/category-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/category-filter.mjs +51 -0
- package/dist/components/compound/search-catalog/category-filter.mjs.map +1 -0
- package/dist/components/compound/search-catalog/column-filter.d.mts +40 -0
- package/dist/components/compound/search-catalog/column-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/column-filter.mjs +63 -0
- package/dist/components/compound/search-catalog/column-filter.mjs.map +1 -0
- package/dist/components/compound/search-catalog/column-filters.d.mts +15 -0
- package/dist/components/compound/search-catalog/column-filters.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/column-filters.mjs +16 -0
- package/dist/components/compound/search-catalog/column-filters.mjs.map +1 -0
- package/dist/components/compound/search-catalog/empty.d.mts +22 -0
- package/dist/components/compound/search-catalog/empty.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/empty.mjs +31 -0
- package/dist/components/compound/search-catalog/empty.mjs.map +1 -0
- package/dist/components/compound/search-catalog/index.d.mts +12 -0
- package/dist/components/compound/search-catalog/index.mjs +14 -0
- package/dist/components/compound/search-catalog/list.d.mts +19 -0
- package/dist/components/compound/search-catalog/list.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/list.mjs +29 -0
- package/dist/components/compound/search-catalog/list.mjs.map +1 -0
- package/dist/components/compound/search-catalog/output-field-filter.d.mts +22 -0
- package/dist/components/compound/search-catalog/output-field-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/output-field-filter.mjs +22 -0
- package/dist/components/compound/search-catalog/output-field-filter.mjs.map +1 -0
- package/dist/components/compound/search-catalog/provider-filter.d.mts +22 -0
- package/dist/components/compound/search-catalog/provider-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/provider-filter.mjs +29 -0
- package/dist/components/compound/search-catalog/provider-filter.mjs.map +1 -0
- package/dist/components/compound/search-catalog/root.d.mts +33 -0
- package/dist/components/compound/search-catalog/root.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/root.mjs +74 -0
- package/dist/components/compound/search-catalog/root.mjs.map +1 -0
- package/dist/components/compound/search-catalog/search-filter.d.mts +24 -0
- package/dist/components/compound/search-catalog/search-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/search-filter.mjs +46 -0
- package/dist/components/compound/search-catalog/search-filter.mjs.map +1 -0
- package/dist/components/compound/search-catalog/tag-filter.d.mts +22 -0
- package/dist/components/compound/search-catalog/tag-filter.d.mts.map +1 -0
- package/dist/components/compound/search-catalog/tag-filter.mjs +22 -0
- package/dist/components/compound/search-catalog/tag-filter.mjs.map +1 -0
- package/dist/components/compound/search-form/content.d.mts +18 -0
- package/dist/components/compound/search-form/content.d.mts.map +1 -0
- package/dist/components/compound/search-form/content.mjs +45 -0
- package/dist/components/compound/search-form/content.mjs.map +1 -0
- package/dist/components/compound/search-form/field.d.mts +17 -0
- package/dist/components/compound/search-form/field.d.mts.map +1 -0
- package/dist/components/compound/search-form/field.mjs +21 -0
- package/dist/components/compound/search-form/field.mjs.map +1 -0
- package/dist/components/compound/search-form/footer.d.mts +14 -0
- package/dist/components/compound/search-form/footer.d.mts.map +1 -0
- package/dist/components/compound/search-form/footer.mjs +14 -0
- package/dist/components/compound/search-form/footer.mjs.map +1 -0
- package/dist/components/compound/search-form/group.d.mts +13 -0
- package/dist/components/compound/search-form/group.d.mts.map +1 -0
- package/dist/components/compound/search-form/group.mjs +17 -0
- package/dist/components/compound/search-form/group.mjs.map +1 -0
- package/dist/components/compound/search-form/header.d.mts +14 -0
- package/dist/components/compound/search-form/header.d.mts.map +1 -0
- package/dist/components/compound/search-form/header.mjs +14 -0
- package/dist/components/compound/search-form/header.mjs.map +1 -0
- package/dist/components/compound/search-form/index.d.mts +9 -0
- package/dist/components/compound/search-form/index.mjs +11 -0
- package/dist/components/compound/search-form/root.d.mts +45 -0
- package/dist/components/compound/search-form/root.d.mts.map +1 -0
- package/dist/components/compound/search-form/root.mjs +90 -0
- package/dist/components/compound/search-form/root.mjs.map +1 -0
- package/dist/components/compound/search-form/section.d.mts +13 -0
- package/dist/components/compound/search-form/section.d.mts.map +1 -0
- package/dist/components/compound/search-form/section.mjs +17 -0
- package/dist/components/compound/search-form/section.mjs.map +1 -0
- package/dist/components/compound/search-form/submit-button.d.mts +9 -0
- package/dist/components/compound/search-form/submit-button.d.mts.map +1 -0
- package/dist/components/compound/search-form/submit-button.mjs +17 -0
- package/dist/components/compound/search-form/submit-button.mjs.map +1 -0
- package/dist/components/compound/search-form/title.d.mts +16 -0
- package/dist/components/compound/search-form/title.d.mts.map +1 -0
- package/dist/components/compound/search-form/title.mjs +14 -0
- package/dist/components/compound/search-form/title.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/active-filters.d.mts +26 -0
- package/dist/components/compound/searches-catalog/active-filters.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/active-filters.mjs +46 -0
- package/dist/components/compound/searches-catalog/active-filters.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/card.d.mts +22 -0
- package/dist/components/compound/searches-catalog/card.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/card.mjs +70 -0
- package/dist/components/compound/searches-catalog/card.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/category-filter.d.mts +29 -0
- package/dist/components/compound/searches-catalog/category-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/category-filter.mjs +51 -0
- package/dist/components/compound/searches-catalog/category-filter.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/column-filter.d.mts +31 -0
- package/dist/components/compound/searches-catalog/column-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/column-filter.mjs +58 -0
- package/dist/components/compound/searches-catalog/column-filter.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/column-filters.d.mts +15 -0
- package/dist/components/compound/searches-catalog/column-filters.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/column-filters.mjs +16 -0
- package/dist/components/compound/searches-catalog/column-filters.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/empty.d.mts +22 -0
- package/dist/components/compound/searches-catalog/empty.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/empty.mjs +31 -0
- package/dist/components/compound/searches-catalog/empty.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/index.d.mts +12 -0
- package/dist/components/compound/searches-catalog/index.mjs +14 -0
- package/dist/components/compound/searches-catalog/list.d.mts +19 -0
- package/dist/components/compound/searches-catalog/list.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/list.mjs +29 -0
- package/dist/components/compound/searches-catalog/list.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/output-field-filter.d.mts +22 -0
- package/dist/components/compound/searches-catalog/output-field-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/output-field-filter.mjs +22 -0
- package/dist/components/compound/searches-catalog/output-field-filter.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/provider-filter.d.mts +22 -0
- package/dist/components/compound/searches-catalog/provider-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/provider-filter.mjs +29 -0
- package/dist/components/compound/searches-catalog/provider-filter.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/root.d.mts +33 -0
- package/dist/components/compound/searches-catalog/root.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/root.mjs +74 -0
- package/dist/components/compound/searches-catalog/root.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/search-filter.d.mts +24 -0
- package/dist/components/compound/searches-catalog/search-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/search-filter.mjs +46 -0
- package/dist/components/compound/searches-catalog/search-filter.mjs.map +1 -0
- package/dist/components/compound/searches-catalog/tag-filter.d.mts +22 -0
- package/dist/components/compound/searches-catalog/tag-filter.d.mts.map +1 -0
- package/dist/components/compound/searches-catalog/tag-filter.mjs +22 -0
- package/dist/components/compound/searches-catalog/tag-filter.mjs.map +1 -0
- package/dist/components/defaults/adapters/async-include-exclude-select-input.mjs +32 -0
- package/dist/components/defaults/adapters/async-include-exclude-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/async-multi-select-input.mjs +26 -0
- package/dist/components/defaults/adapters/async-multi-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/boolean-input.mjs +82 -0
- package/dist/components/defaults/adapters/boolean-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/connector-input.mjs +94 -0
- package/dist/components/defaults/adapters/connector-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/context-select-input.mjs +74 -0
- package/dist/components/defaults/adapters/context-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/cursor-pagination-input.mjs +29 -0
- package/dist/components/defaults/adapters/cursor-pagination-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/date-range-input.mjs +53 -0
- package/dist/components/defaults/adapters/date-range-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/exact-range-input.mjs +75 -0
- package/dist/components/defaults/adapters/exact-range-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/fields-select-input.mjs +25 -0
- package/dist/components/defaults/adapters/fields-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/include-exclude-input.mjs +33 -0
- package/dist/components/defaults/adapters/include-exclude-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/include-exclude-select-input.mjs +36 -0
- package/dist/components/defaults/adapters/include-exclude-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/index.d.mts +11 -0
- package/dist/components/defaults/adapters/index.d.mts.map +1 -0
- package/dist/components/defaults/adapters/index.mjs +73 -0
- package/dist/components/defaults/adapters/index.mjs.map +1 -0
- package/dist/components/defaults/adapters/int-input.mjs +16 -0
- package/dist/components/defaults/adapters/int-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/json-extraction-input.mjs +333 -0
- package/dist/components/defaults/adapters/json-extraction-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/json-schema-input.mjs +30 -0
- package/dist/components/defaults/adapters/json-schema-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/key-value-list-input.mjs +100 -0
- package/dist/components/defaults/adapters/key-value-list-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/min-max-int-input.mjs +65 -0
- package/dist/components/defaults/adapters/min-max-int-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/multi-create-input.mjs +32 -0
- package/dist/components/defaults/adapters/multi-create-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/multi-select-input.mjs +26 -0
- package/dist/components/defaults/adapters/multi-select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/number-input.mjs +15 -0
- package/dist/components/defaults/adapters/number-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/ordered-multi-create-input.mjs +43 -0
- package/dist/components/defaults/adapters/ordered-multi-create-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/output-field-input.mjs +37 -0
- package/dist/components/defaults/adapters/output-field-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/pipes-trigger-input.mjs +381 -0
- package/dist/components/defaults/adapters/pipes-trigger-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/prompt-input.mjs +208 -0
- package/dist/components/defaults/adapters/prompt-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/providers-input.mjs +23 -0
- package/dist/components/defaults/adapters/providers-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/range-input.mjs +61 -0
- package/dist/components/defaults/adapters/range-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/select-input.mjs +54 -0
- package/dist/components/defaults/adapters/select-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/tagged-text-input.mjs +154 -0
- package/dist/components/defaults/adapters/tagged-text-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/template-input.mjs +34 -0
- package/dist/components/defaults/adapters/template-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/text-input.mjs +18 -0
- package/dist/components/defaults/adapters/text-input.mjs.map +1 -0
- package/dist/components/defaults/adapters/textarea-input.mjs +17 -0
- package/dist/components/defaults/adapters/textarea-input.mjs.map +1 -0
- package/dist/components/defaults/catalog/active-filter-pill.mjs +30 -0
- package/dist/components/defaults/catalog/active-filter-pill.mjs.map +1 -0
- package/dist/components/defaults/catalog/card-derived.d.mts +98 -0
- package/dist/components/defaults/catalog/card-derived.d.mts.map +1 -0
- package/dist/components/defaults/catalog/card-derived.mjs +172 -0
- package/dist/components/defaults/catalog/card-derived.mjs.map +1 -0
- package/dist/components/defaults/catalog/card-primitives.d.mts +81 -0
- package/dist/components/defaults/catalog/card-primitives.d.mts.map +1 -0
- package/dist/components/defaults/catalog/card-primitives.mjs +108 -0
- package/dist/components/defaults/catalog/card-primitives.mjs.map +1 -0
- package/dist/components/defaults/catalog/category-filter.d.mts +13 -0
- package/dist/components/defaults/catalog/category-filter.d.mts.map +1 -0
- package/dist/components/defaults/catalog/category-filter.mjs +28 -0
- package/dist/components/defaults/catalog/category-filter.mjs.map +1 -0
- package/dist/components/defaults/catalog/category-section.d.mts +39 -0
- package/dist/components/defaults/catalog/category-section.d.mts.map +1 -0
- package/dist/components/defaults/catalog/category-section.mjs +59 -0
- package/dist/components/defaults/catalog/category-section.mjs.map +1 -0
- package/dist/components/defaults/catalog/empty-state.mjs +20 -0
- package/dist/components/defaults/catalog/empty-state.mjs.map +1 -0
- package/dist/components/defaults/catalog/filter-select.d.mts +13 -0
- package/dist/components/defaults/catalog/filter-select.d.mts.map +1 -0
- package/dist/components/defaults/catalog/filter-select.mjs +45 -0
- package/dist/components/defaults/catalog/filter-select.mjs.map +1 -0
- package/dist/components/defaults/catalog/layout.mjs +53 -0
- package/dist/components/defaults/catalog/layout.mjs.map +1 -0
- package/dist/components/defaults/catalog/provider-avatars.d.mts +37 -0
- package/dist/components/defaults/catalog/provider-avatars.d.mts.map +1 -0
- package/dist/components/defaults/catalog/provider-avatars.mjs +98 -0
- package/dist/components/defaults/catalog/provider-avatars.mjs.map +1 -0
- package/dist/components/defaults/field-section-enumeration.mjs +32 -0
- package/dist/components/defaults/field-section-enumeration.mjs.map +1 -0
- package/dist/components/defaults/layout/field-wrapper.d.mts +13 -0
- package/dist/components/defaults/layout/field-wrapper.d.mts.map +1 -0
- package/dist/components/defaults/layout/field-wrapper.mjs +67 -0
- package/dist/components/defaults/layout/field-wrapper.mjs.map +1 -0
- package/dist/components/defaults/layout/form.mjs +21 -0
- package/dist/components/defaults/layout/form.mjs.map +1 -0
- package/dist/components/defaults/layout/group.d.mts +16 -0
- package/dist/components/defaults/layout/group.d.mts.map +1 -0
- package/dist/components/defaults/layout/group.mjs +87 -0
- package/dist/components/defaults/layout/group.mjs.map +1 -0
- package/dist/components/defaults/layout/section.d.mts +14 -0
- package/dist/components/defaults/layout/section.d.mts.map +1 -0
- package/dist/components/defaults/layout/section.mjs +39 -0
- package/dist/components/defaults/layout/section.mjs.map +1 -0
- package/dist/components/defaults/layout/submit-button.d.mts +9 -0
- package/dist/components/defaults/layout/submit-button.d.mts.map +1 -0
- package/dist/components/defaults/layout/submit-button.mjs +23 -0
- package/dist/components/defaults/layout/submit-button.mjs.map +1 -0
- package/dist/components/defaults/toggle-advanced-button.mjs +29 -0
- package/dist/components/defaults/toggle-advanced-button.mjs.map +1 -0
- package/dist/components/field-renderer.d.mts +14 -0
- package/dist/components/field-renderer.d.mts.map +1 -0
- package/dist/components/field-renderer.mjs +21 -0
- package/dist/components/field-renderer.mjs.map +1 -0
- package/dist/components/hover-info.mjs +30 -0
- package/dist/components/hover-info.mjs.map +1 -0
- package/dist/components/internal/LiquidEditor/ChipEditPopover.mjs +319 -0
- package/dist/components/internal/LiquidEditor/ChipEditPopover.mjs.map +1 -0
- package/dist/components/internal/LiquidEditor/LiquidEditor.mjs +208 -0
- package/dist/components/internal/LiquidEditor/LiquidEditor.mjs.map +1 -0
- package/dist/components/internal/LiquidEditor/UnifiedReferencePicker.mjs +240 -0
- package/dist/components/internal/LiquidEditor/UnifiedReferencePicker.mjs.map +1 -0
- package/dist/components/internal/combobox/include-exclude-combobox.mjs +368 -0
- package/dist/components/internal/combobox/include-exclude-combobox.mjs.map +1 -0
- package/dist/components/internal/combobox/suggest-combobox.mjs +294 -0
- package/dist/components/internal/combobox/suggest-combobox.mjs.map +1 -0
- package/dist/components/internal/field-legend.mjs +37 -0
- package/dist/components/internal/field-legend.mjs.map +1 -0
- package/dist/components/internal/form-level-errors.mjs +71 -0
- package/dist/components/internal/form-level-errors.mjs.map +1 -0
- package/dist/components/internal/icons.mjs +131 -0
- package/dist/components/internal/icons.mjs.map +1 -0
- package/dist/components/internal/multi-select-popover-trigger.mjs +26 -0
- package/dist/components/internal/multi-select-popover-trigger.mjs.map +1 -0
- package/dist/components/internal/schema-editor/SchemaEditor.mjs +468 -0
- package/dist/components/internal/schema-editor/SchemaEditor.mjs.map +1 -0
- package/dist/components/internal/schema-editor/generate-schema-rows.mjs +374 -0
- package/dist/components/internal/schema-editor/generate-schema-rows.mjs.map +1 -0
- package/dist/components/internal/schema-editor/schema-editor-context.mjs +32 -0
- package/dist/components/internal/schema-editor/schema-editor-context.mjs.map +1 -0
- package/dist/components/internal/schema-editor/schema-utils.mjs +249 -0
- package/dist/components/internal/schema-editor/schema-utils.mjs.map +1 -0
- package/dist/components/internal/suggestion-menu/suggestion-menu-utils.mjs +12 -0
- package/dist/components/internal/suggestion-menu/suggestion-menu-utils.mjs.map +1 -0
- package/dist/components/internal/suggestion-menu/suggestion-menu.mjs +151 -0
- package/dist/components/internal/suggestion-menu/suggestion-menu.mjs.map +1 -0
- package/dist/components/internal/tag-chip-decoration.mjs +180 -0
- package/dist/components/internal/tag-chip-decoration.mjs.map +1 -0
- package/dist/components/rich-text.mjs +42 -0
- package/dist/components/rich-text.mjs.map +1 -0
- package/dist/components/ui/badge.mjs +32 -0
- package/dist/components/ui/badge.mjs.map +1 -0
- package/dist/components/ui/button.d.mts +19 -0
- package/dist/components/ui/button.d.mts.map +1 -0
- package/dist/components/ui/button.mjs +47 -0
- package/dist/components/ui/button.mjs.map +1 -0
- package/dist/components/ui/combobox.mjs +103 -0
- package/dist/components/ui/combobox.mjs.map +1 -0
- package/dist/components/ui/input-group.mjs +30 -0
- package/dist/components/ui/input-group.mjs.map +1 -0
- package/dist/components/ui/input.mjs +17 -0
- package/dist/components/ui/input.mjs.map +1 -0
- package/dist/components/ui/label.mjs +17 -0
- package/dist/components/ui/label.mjs.map +1 -0
- package/dist/components/ui/popover.mjs +40 -0
- package/dist/components/ui/popover.mjs.map +1 -0
- package/dist/components/ui/select.mjs +92 -0
- package/dist/components/ui/select.mjs.map +1 -0
- package/dist/components/ui/switch.mjs +21 -0
- package/dist/components/ui/switch.mjs.map +1 -0
- package/dist/components/ui/table.mjs +56 -0
- package/dist/components/ui/table.mjs.map +1 -0
- package/dist/components/ui/textarea.mjs +15 -0
- package/dist/components/ui/textarea.mjs.map +1 -0
- package/dist/components/ui/tooltip.mjs +48 -0
- package/dist/components/ui/tooltip.mjs.map +1 -0
- package/dist/context/catalog-card-context.mjs +31 -0
- package/dist/context/catalog-card-context.mjs.map +1 -0
- package/dist/context/catalog-config-context.d.mts +43 -0
- package/dist/context/catalog-config-context.d.mts.map +1 -0
- package/dist/context/catalog-config-context.mjs +48 -0
- package/dist/context/catalog-config-context.mjs.map +1 -0
- package/dist/context/form-context.mjs +11 -0
- package/dist/context/form-context.mjs.map +1 -0
- package/dist/context/form-customization-context.d.mts +71 -0
- package/dist/context/form-customization-context.d.mts.map +1 -0
- package/dist/context/form-customization-context.mjs +114 -0
- package/dist/context/form-customization-context.mjs.map +1 -0
- package/dist/context/form-provider.d.mts +41 -0
- package/dist/context/form-provider.d.mts.map +1 -0
- package/dist/context/form-provider.mjs +53 -0
- package/dist/context/form-provider.mjs.map +1 -0
- package/dist/context/pipe-catalog-card-context.d.mts +17 -0
- package/dist/context/pipe-catalog-card-context.d.mts.map +1 -0
- package/dist/context/pipe-catalog-card-context.mjs +13 -0
- package/dist/context/pipe-catalog-card-context.mjs.map +1 -0
- package/dist/context/pipe-catalog-context.d.mts +26 -0
- package/dist/context/pipe-catalog-context.d.mts.map +1 -0
- package/dist/context/pipe-catalog-context.mjs +13 -0
- package/dist/context/pipe-catalog-context.mjs.map +1 -0
- package/dist/context/pipe-form-context.d.mts +25 -0
- package/dist/context/pipe-form-context.d.mts.map +1 -0
- package/dist/context/pipe-form-context.mjs +13 -0
- package/dist/context/pipe-form-context.mjs.map +1 -0
- package/dist/context/portal-container-context.d.mts +5 -0
- package/dist/context/portal-container-context.d.mts.map +1 -0
- package/dist/context/portal-container-context.mjs +15 -0
- package/dist/context/portal-container-context.mjs.map +1 -0
- package/dist/context/search-catalog-card-context.d.mts +16 -0
- package/dist/context/search-catalog-card-context.d.mts.map +1 -0
- package/dist/context/search-catalog-card-context.mjs +13 -0
- package/dist/context/search-catalog-card-context.mjs.map +1 -0
- package/dist/context/search-catalog-context.d.mts +20 -0
- package/dist/context/search-catalog-context.d.mts.map +1 -0
- package/dist/context/search-catalog-context.mjs +13 -0
- package/dist/context/search-catalog-context.mjs.map +1 -0
- package/dist/context/search-form-context.d.mts +25 -0
- package/dist/context/search-form-context.d.mts.map +1 -0
- package/dist/context/search-form-context.mjs +13 -0
- package/dist/context/search-form-context.mjs.map +1 -0
- package/dist/context/searches-catalog-card-context.d.mts +16 -0
- package/dist/context/searches-catalog-card-context.d.mts.map +1 -0
- package/dist/context/searches-catalog-card-context.mjs +13 -0
- package/dist/context/searches-catalog-card-context.mjs.map +1 -0
- package/dist/context/searches-catalog-context.d.mts +20 -0
- package/dist/context/searches-catalog-context.d.mts.map +1 -0
- package/dist/context/searches-catalog-context.mjs +13 -0
- package/dist/context/searches-catalog-context.mjs.map +1 -0
- package/dist/hooks/use-debounce.mjs +28 -0
- package/dist/hooks/use-debounce.mjs.map +1 -0
- package/dist/hooks/use-debounced-fn.mjs +47 -0
- package/dist/hooks/use-debounced-fn.mjs.map +1 -0
- package/dist/hooks/use-disclosure.mjs +35 -0
- package/dist/hooks/use-disclosure.mjs.map +1 -0
- package/dist/hooks/use-field-error.d.mts +11 -0
- package/dist/hooks/use-field-error.d.mts.map +1 -0
- package/dist/hooks/use-field-error.mjs +23 -0
- package/dist/hooks/use-field-error.mjs.map +1 -0
- package/dist/hooks/use-floating-element.mjs +45 -0
- package/dist/hooks/use-floating-element.mjs.map +1 -0
- package/dist/hooks/use-form-core.d.mts +16 -0
- package/dist/hooks/use-form-core.d.mts.map +1 -0
- package/dist/hooks/use-form-core.mjs +241 -0
- package/dist/hooks/use-form-core.mjs.map +1 -0
- package/dist/hooks/use-jsonata-preview.mjs +38 -0
- package/dist/hooks/use-jsonata-preview.mjs.map +1 -0
- package/dist/hooks/use-menu-navigation.mjs +86 -0
- package/dist/hooks/use-menu-navigation.mjs.map +1 -0
- package/dist/hooks/use-pipe-catalog-table.d.mts +47 -0
- package/dist/hooks/use-pipe-catalog-table.d.mts.map +1 -0
- package/dist/hooks/use-pipe-catalog-table.mjs +170 -0
- package/dist/hooks/use-pipe-catalog-table.mjs.map +1 -0
- package/dist/hooks/use-pipe-form.d.mts +31 -0
- package/dist/hooks/use-pipe-form.d.mts.map +1 -0
- package/dist/hooks/use-pipe-form.mjs +65 -0
- package/dist/hooks/use-pipe-form.mjs.map +1 -0
- package/dist/hooks/use-search-catalog-table.d.mts +40 -0
- package/dist/hooks/use-search-catalog-table.d.mts.map +1 -0
- package/dist/hooks/use-search-catalog-table.mjs +161 -0
- package/dist/hooks/use-search-catalog-table.mjs.map +1 -0
- package/dist/hooks/use-search-form.d.mts +17 -0
- package/dist/hooks/use-search-form.d.mts.map +1 -0
- package/dist/hooks/use-search-form.mjs +58 -0
- package/dist/hooks/use-search-form.mjs.map +1 -0
- package/dist/hooks/use-searches-catalog-table.d.mts +40 -0
- package/dist/hooks/use-searches-catalog-table.d.mts.map +1 -0
- package/dist/hooks/use-searches-catalog-table.mjs +161 -0
- package/dist/hooks/use-searches-catalog-table.mjs.map +1 -0
- package/dist/index.d.mts +96 -0
- package/dist/index.mjs +98 -0
- package/dist/lib/utils.mjs +11 -0
- package/dist/lib/utils.mjs.map +1 -0
- package/dist/styles/pipe0-form.css +3785 -0
- package/dist/types/adapters.d.mts +107 -0
- package/dist/types/adapters.d.mts.map +1 -0
- package/dist/types/catalog-adapters.d.mts +122 -0
- package/dist/types/catalog-adapters.d.mts.map +1 -0
- package/dist/types/field-handle.d.mts +3 -0
- package/dist/types/field-props.d.mts +285 -0
- package/dist/types/field-props.d.mts.map +1 -0
- package/dist/types/form-customization.d.mts +25 -0
- package/dist/types/form-customization.d.mts.map +1 -0
- package/dist/types/form-handle.d.mts +23 -0
- package/dist/types/form-handle.d.mts.map +1 -0
- package/dist/utils/build-section-handlers.mjs +419 -0
- package/dist/utils/build-section-handlers.mjs.map +1 -0
- package/dist/utils/catalog-helpers.d.mts +12 -0
- package/dist/utils/catalog-helpers.d.mts.map +1 -0
- package/dist/utils/catalog-helpers.mjs +35 -0
- package/dist/utils/catalog-helpers.mjs.map +1 -0
- package/dist/utils/generate-random-string.mjs +11 -0
- package/dist/utils/generate-random-string.mjs.map +1 -0
- package/dist/utils/merge-form-stores.mjs +14 -0
- package/dist/utils/merge-form-stores.mjs.map +1 -0
- package/dist/utils/object-path.mjs +72 -0
- package/dist/utils/object-path.mjs.map +1 -0
- package/dist/utils/render-slot.d.mts +44 -0
- package/dist/utils/render-slot.d.mts.map +1 -0
- package/dist/utils/render-slot.mjs +30 -0
- package/dist/utils/render-slot.mjs.map +1 -0
- package/dist/widgets/avatar-group.d.mts +36 -0
- package/dist/widgets/avatar-group.d.mts.map +1 -0
- package/dist/widgets/avatar-group.mjs +114 -0
- package/dist/widgets/avatar-group.mjs.map +1 -0
- package/dist/widgets/emoji-glyph.d.mts +11 -0
- package/dist/widgets/emoji-glyph.d.mts.map +1 -0
- package/dist/widgets/emoji-glyph.mjs +13 -0
- package/dist/widgets/emoji-glyph.mjs.map +1 -0
- package/dist/widgets/field-type-badge.d.mts +13 -0
- package/dist/widgets/field-type-badge.d.mts.map +1 -0
- package/dist/widgets/field-type-badge.mjs +30 -0
- package/dist/widgets/field-type-badge.mjs.map +1 -0
- package/dist/widgets/icon-glyph.d.mts +16 -0
- package/dist/widgets/icon-glyph.d.mts.map +1 -0
- package/dist/widgets/icon-glyph.mjs +59 -0
- package/dist/widgets/icon-glyph.mjs.map +1 -0
- package/dist/widgets/index.d.mts +9 -0
- package/dist/widgets/index.mjs +11 -0
- package/dist/widgets/logo-url.d.mts +17 -0
- package/dist/widgets/logo-url.d.mts.map +1 -0
- package/dist/widgets/logo-url.mjs +17 -0
- package/dist/widgets/logo-url.mjs.map +1 -0
- package/dist/widgets/pricing-badge.d.mts +11 -0
- package/dist/widgets/pricing-badge.d.mts.map +1 -0
- package/dist/widgets/pricing-badge.mjs +13 -0
- package/dist/widgets/pricing-badge.mjs.map +1 -0
- package/dist/widgets/provider-logo.d.mts +16 -0
- package/dist/widgets/provider-logo.d.mts.map +1 -0
- package/dist/widgets/provider-logo.mjs +20 -0
- package/dist/widgets/provider-logo.mjs.map +1 -0
- package/dist/widgets/widget-strip.d.mts +16 -0
- package/dist/widgets/widget-strip.d.mts.map +1 -0
- package/dist/widgets/widget-strip.mjs +42 -0
- package/dist/widgets/widget-strip.mjs.map +1 -0
- package/dist/widgets/widget-view.d.mts +14 -0
- package/dist/widgets/widget-view.d.mts.map +1 -0
- package/dist/widgets/widget-view.mjs +36 -0
- package/dist/widgets/widget-view.mjs.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChipEditPopover.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/ChipEditPopover.tsx"],"sourcesContent":["import { offset, shift } from \"@floating-ui/react\";\nimport type { Editor } from \"@tiptap/react\";\nimport { ExternalLink, Trash2 } from \"lucide-react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { useFloatingElement } from \"../../../hooks/use-floating-element.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\nimport { Switch } from \"../../ui/switch.js\";\nimport type { ChipKind } from \"../tag-chip-decoration.js\";\n\nconst SIMPLE_FIELD_RE = /^\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_.]*)\\s*(\\|\\s*default:\\s*\"\")?\\s*\\}\\}$/;\nconst SECRET_RE = /^\\{\\{\\s*SECRETS\\.([A-Z][A-Z0-9_]*)\\s*\\}\\}$/;\n// Captures `name`, `type` (string|number|boolean|json|unknown), and `description`\n// from `{% output NAME, type: \"TYPE\", description: \"...\" %}` or with a `schema:`\n// arg between type and description for json. Tolerates whitespace and ordering.\nconst OUTPUT_BLOCK_RE =\n /^\\{%\\s*output\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*,\\s*type:\\s*\"(string|number|boolean|json|unknown)\"\\s*(?:,\\s*schema:\\s*\"([^\"]*)\")?\\s*(?:,\\s*description:\\s*\"((?:[^\"\\\\]|\\\\.)*)\")?\\s*%\\}$/;\n\nexport interface ChipEditTarget {\n kind: ChipKind;\n raw: string;\n from: number;\n to: number;\n rect: DOMRect;\n}\n\n/**\n * Contextual popover anchored to a chip's DOM rect. Different content per\n * chip kind:\n * - field: switch for `| default: \"\"` (simple cases only), remove.\n * - secret: publicId header, manage/remove buttons. Power users still\n * edit by hand.\n * - block (output declaration): name / type / description editors.\n *\n * On any mutation, the popover dispatches a single replaceWith transaction\n * over the chip's range, then closes itself. The Liquid serialization\n * stays identical to what would have been authored by hand.\n */\nexport function ChipEditPopover({\n editor,\n target,\n onClose,\n}: {\n editor: Editor;\n target: ChipEditTarget;\n onClose: () => void;\n}) {\n const { ref, style, isMounted, getFloatingProps } = useFloatingElement(true, target.rect, 1100, {\n placement: \"bottom-start\",\n middleware: [offset(6), shift()],\n onOpenChange(open) {\n if (!open) onClose();\n },\n dismissOptions: { outsidePress: true, outsidePressEvent: \"mousedown\" },\n });\n\n const popupRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") onClose();\n }\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onClose]);\n\n function replaceWith(next: string) {\n editor.chain().focus().insertContentAt({ from: target.from, to: target.to }, next).run();\n onClose();\n }\n\n function remove() {\n editor.chain().focus().deleteRange({ from: target.from, to: target.to }).run();\n onClose();\n }\n\n if (!isMounted) return null;\n\n return (\n <div\n ref={(el) => {\n popupRef.current = el;\n ref(el);\n }}\n style={style}\n {...getFloatingProps()}\n onMouseDown={(e) => e.stopPropagation()}\n className=\"pz:flex pz:flex-col pz:gap-2 pz:rounded-md pz:border pz:border-input pz:bg-popover pz:p-3 pz:text-popover-foreground pz:shadow-md pz:min-w-72\"\n role=\"dialog\"\n aria-label={`Edit ${target.kind} chip`}\n >\n {target.kind === \"field\" && (\n <FieldChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n {target.kind === \"secret\" && <SecretChipBody raw={target.raw} remove={remove} />}\n {target.kind === \"block\" && (\n <BlockChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n </div>\n );\n}\n\nfunction FieldChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const match = raw.match(SIMPLE_FIELD_RE);\n const name = match?.[1];\n const allowEmpty = !!match?.[2];\n const isSimple = !!match;\n\n if (!isSimple || !name) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Field reference (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This chip uses a custom Liquid filter chain. Edit the raw text in the editor to change it.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function toggleAllowEmpty() {\n replaceWith(allowEmpty ? `{{ ${name} }}` : `{{ ${name} | default: \"\" }}`);\n }\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Field reference</span>\n <code className=\"pz:text-xs pz:text-sky-700\">{name}</code>\n </header>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-3 pz:text-sm\">\n <span className=\"pz:flex pz:flex-col\">\n <span>Allow empty</span>\n <span className=\"pz:text-xs pz:text-muted-foreground\">\n Inserts <code>| default: \"\"</code> so missing values render as empty.\n </span>\n </span>\n <Switch checked={allowEmpty} onCheckedChange={toggleAllowEmpty} />\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction SecretChipBody({ raw, remove }: { raw: string; remove: () => void }) {\n const publicId = raw.match(SECRET_RE)?.[1];\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Secret reference</span>\n <code className=\"pz:text-xs pz:text-amber-700\">{publicId ?? \"(unknown)\"}</code>\n </header>\n <div className=\"pz:flex pz:items-center pz:gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => window.open(\"/secrets\", \"_blank\", \"noopener\")}\n >\n <ExternalLink className=\"pz:size-3.5 pz:mr-1\" />\n Manage secrets\n </Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </div>\n </>\n );\n}\n\nfunction BlockChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const initial = useMemo(() => {\n const m = raw.match(OUTPUT_BLOCK_RE);\n if (!m) return null;\n const [, name, type, schema, description] = m;\n return {\n name,\n type: type as \"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\",\n schema: schema ?? \"\",\n description: description ? description.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\") : \"\",\n };\n }, [raw]);\n\n const [name, setName] = useState(initial?.name ?? \"\");\n const [type, setType] = useState<\"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\">(\n initial?.type ?? \"string\",\n );\n const [schema, setSchema] = useState(initial?.schema ?? \"\");\n const [description, setDescription] = useState(initial?.description ?? \"\");\n const idPrefix = useId();\n const nameId = `${idPrefix}-name`;\n const typeId = `${idPrefix}-type`;\n const schemaId = `${idPrefix}-schema`;\n const descId = `${idPrefix}-desc`;\n\n if (!initial) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Block (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This block uses a non-standard form. Edit the raw text in the editor.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function save() {\n if (!name.trim()) return;\n const escaped = description.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n const parts = [`{% output ${name.trim()}`, `type: \"${type}\"`];\n if (type === \"json\" && schema.trim()) parts.push(`schema: \"${schema.trim()}\"`);\n parts.push(`description: \"${escaped}\"`);\n replaceWith(`${parts.join(\", \")} %}`);\n }\n\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Output declaration\n </header>\n <label htmlFor={nameId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Name</span>\n <Input\n id={nameId}\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"FIELD_NAME\"\n />\n </label>\n <label htmlFor={typeId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Type</span>\n <select\n id={typeId}\n value={type}\n onChange={(e) =>\n setType(e.target.value as \"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\")\n }\n className=\"pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm\"\n >\n <option value=\"string\">string</option>\n <option value=\"number\">number</option>\n <option value=\"boolean\">boolean</option>\n <option value=\"json\">json</option>\n <option value=\"unknown\">unknown</option>\n </select>\n </label>\n {type === \"json\" && (\n <label htmlFor={schemaId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Schema</span>\n <Input\n id={schemaId}\n value={schema}\n onChange={(e) => setSchema(e.target.value)}\n placeholder=\"SCHEMA_NAME\"\n />\n </label>\n )}\n <label htmlFor={descId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Description</span>\n <Input id={descId} value={description} onChange={(e) => setDescription(e.target.value)} />\n </label>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-2 pz:pt-1\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={save}>\n Save\n </Button>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.mjs";
|
|
2
|
+
import { FieldLegend } from "../field-legend.mjs";
|
|
3
|
+
import { SuggestionMenu } from "../suggestion-menu/suggestion-menu.mjs";
|
|
4
|
+
import { TagChipDecoration } from "../tag-chip-decoration.mjs";
|
|
5
|
+
import { ChipEditPopover } from "./ChipEditPopover.mjs";
|
|
6
|
+
import { UnifiedReferencePicker, buildReferenceItems } from "./UnifiedReferencePicker.mjs";
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { RECORD_FIELD_TYPES } from "@pipe0/base";
|
|
10
|
+
import { EditorContent, EditorContext, useEditor } from "@tiptap/react";
|
|
11
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
12
|
+
|
|
13
|
+
//#region src/components/internal/LiquidEditor/LiquidEditor.tsx
|
|
14
|
+
const SECRET_SEARCH_DEBOUNCE_MS = 150;
|
|
15
|
+
function escapeHtml(s) {
|
|
16
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reconciles single- and multi-line text into Tiptap-friendly HTML.
|
|
20
|
+
* - Single-line: collapses whitespace runs containing newlines into a
|
|
21
|
+
* single space and renders as one paragraph.
|
|
22
|
+
* - Multi-line: paragraphs separated by blank lines (`\n\n+`); soft
|
|
23
|
+
* breaks within a paragraph render as `<br>`. Leading spaces on each
|
|
24
|
+
* line are preserved with ` ` so JSON-shaped payloads round-trip
|
|
25
|
+
* through the editor.
|
|
26
|
+
*/
|
|
27
|
+
function textToTiptapHTML(text, multiline) {
|
|
28
|
+
if (!multiline) return `<p>${escapeHtml(text.replace(/\s*\n+\s*/g, " "))}</p>`;
|
|
29
|
+
return escapeHtml(text).split(/\n\n+/).map((block) => {
|
|
30
|
+
return `<p>${block.split(/\n/).map((line) => line.replace(/^ +/, (spaces) => " ".repeat(spaces.length))).join("<br>")}</p>`;
|
|
31
|
+
}).join("");
|
|
32
|
+
}
|
|
33
|
+
const OUTPUT_TEMPLATE = (fieldType) => {
|
|
34
|
+
if (fieldType === "json") return `{% output FIELD_NAME, type: "json", schema: "SCHEMA_NAME", description: "" %}`;
|
|
35
|
+
return `{% output FIELD_NAME, type: "${fieldType}", description: "" %}`;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Single editor surface for every form field that accepts Liquid tags.
|
|
39
|
+
* Two triggers, two cognitive categories:
|
|
40
|
+
*
|
|
41
|
+
* - `/` opens a unified reference picker (Fields, Secrets, Constants).
|
|
42
|
+
* Prefix syntax `/f/`, `/s/`, `/c/` filters to one source. Picking
|
|
43
|
+
* emits the corresponding `{{ … }}` Liquid Output.
|
|
44
|
+
*
|
|
45
|
+
* - `@` opens a directives picker (only when `directives.length > 0`).
|
|
46
|
+
* Today the only directive is `output`, which inserts a templated
|
|
47
|
+
* `{% output FIELD_NAME, type: "...", description: "" %}` block.
|
|
48
|
+
*
|
|
49
|
+
* Chips render via the `TagChipDecoration` extension. Click or
|
|
50
|
+
* Enter/Space on a chip mounts the contextual `ChipEditPopover`.
|
|
51
|
+
*
|
|
52
|
+
* Backwards compat: the persisted value is plain Liquid text,
|
|
53
|
+
* byte-identical to what the legacy `TagEditor` / `TextPromptEditor`
|
|
54
|
+
* produced. No engine, analyzer, or metadata changes.
|
|
55
|
+
*/
|
|
56
|
+
function LiquidEditor({ value, onChange, inputFields, searchSecrets, constantSuggestions, multiline = false, autoGrow = true, directives = [], expectedFieldType, placeholder, className, editorProps, hideLegend = false }) {
|
|
57
|
+
const blockSeparator = multiline ? "\n" : "";
|
|
58
|
+
const visibleConstants = constantSuggestions ?? [];
|
|
59
|
+
const supportsOutput = directives.includes("output");
|
|
60
|
+
const hasSecretsResolver = !!searchSecrets;
|
|
61
|
+
const [chipTarget, setChipTarget] = useState(null);
|
|
62
|
+
const tagChipExtension = useMemo(() => TagChipDecoration.configure({ onChipClick: (hit, el) => {
|
|
63
|
+
setChipTarget({
|
|
64
|
+
kind: hit.kind,
|
|
65
|
+
raw: hit.raw,
|
|
66
|
+
from: hit.from,
|
|
67
|
+
to: hit.to,
|
|
68
|
+
rect: el.getBoundingClientRect()
|
|
69
|
+
});
|
|
70
|
+
} }), []);
|
|
71
|
+
const editor = useEditor({
|
|
72
|
+
extensions: [StarterKit.configure({ hardBreak: !multiline ? false : void 0 }), tagChipExtension],
|
|
73
|
+
parseOptions: { preserveWhitespace: "full" },
|
|
74
|
+
editorProps: {
|
|
75
|
+
...editorProps,
|
|
76
|
+
attributes: {
|
|
77
|
+
class: cn("pz:px-2.5 pz:py-1 pz:text-sm pz:outline-none pz:break-words", multiline ? autoGrow ? "pz:min-h-24 pz:max-h-96 pz:overflow-auto pz:whitespace-pre-wrap" : "pz:overflow-auto pz:whitespace-pre-wrap" : "pz:min-h-8", className),
|
|
78
|
+
...placeholder ? { "data-placeholder": placeholder } : {},
|
|
79
|
+
...editorProps?.attributes
|
|
80
|
+
},
|
|
81
|
+
handleKeyDown(view, event) {
|
|
82
|
+
if (editorProps?.handleKeyDown?.(view, event)) return true;
|
|
83
|
+
if (!multiline && event.key === "Enter") return true;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
content: textToTiptapHTML(value || "", multiline),
|
|
88
|
+
onUpdate({ editor }) {
|
|
89
|
+
onChange(editor.getText({ blockSeparator }));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!editor) return;
|
|
94
|
+
if (editor.getText({ blockSeparator }) === (value ?? "")) return;
|
|
95
|
+
editor.commands.setContent(textToTiptapHTML(value ?? "", multiline), false);
|
|
96
|
+
}, [
|
|
97
|
+
editor,
|
|
98
|
+
value,
|
|
99
|
+
multiline,
|
|
100
|
+
blockSeparator
|
|
101
|
+
]);
|
|
102
|
+
const insertField = useCallback((name) => `{{ ${name} }}`, []);
|
|
103
|
+
const lastSecretsRef = useRef([]);
|
|
104
|
+
const latestQueryRef = useRef("");
|
|
105
|
+
const referenceItems = useCallback(({ query }) => {
|
|
106
|
+
latestQueryRef.current = query;
|
|
107
|
+
const myQuery = query;
|
|
108
|
+
const buildWith = (secrets) => buildReferenceItems(myQuery, {
|
|
109
|
+
inputFields,
|
|
110
|
+
secretSuggestions: secrets,
|
|
111
|
+
constantSuggestions: visibleConstants
|
|
112
|
+
}, expectedFieldType, insertField);
|
|
113
|
+
if (!searchSecrets) return Promise.resolve(buildWith([]));
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
setTimeout(async () => {
|
|
116
|
+
if (latestQueryRef.current !== myQuery) {
|
|
117
|
+
resolve(buildWith(lastSecretsRef.current));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const secrets = await searchSecrets(myQuery);
|
|
122
|
+
if (latestQueryRef.current !== myQuery) {
|
|
123
|
+
resolve(buildWith(lastSecretsRef.current));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
lastSecretsRef.current = secrets;
|
|
127
|
+
resolve(buildWith(secrets));
|
|
128
|
+
} catch {
|
|
129
|
+
resolve(buildWith(lastSecretsRef.current));
|
|
130
|
+
}
|
|
131
|
+
}, SECRET_SEARCH_DEBOUNCE_MS);
|
|
132
|
+
});
|
|
133
|
+
}, [
|
|
134
|
+
searchSecrets,
|
|
135
|
+
inputFields,
|
|
136
|
+
visibleConstants,
|
|
137
|
+
expectedFieldType,
|
|
138
|
+
insertField
|
|
139
|
+
]);
|
|
140
|
+
const directiveItems = useCallback(() => RECORD_FIELD_TYPES.map((fieldType) => ({
|
|
141
|
+
title: `output: ${fieldType}`,
|
|
142
|
+
keywords: [fieldType, "output"],
|
|
143
|
+
onSelect: ({ editor: ed, range }) => {
|
|
144
|
+
ed.chain().focus().insertContentAt(range, OUTPUT_TEMPLATE(fieldType)).run();
|
|
145
|
+
}
|
|
146
|
+
})), []);
|
|
147
|
+
const legendEntries = [];
|
|
148
|
+
legendEntries.push({
|
|
149
|
+
key: "/",
|
|
150
|
+
label: "to insert a reference"
|
|
151
|
+
});
|
|
152
|
+
if (supportsOutput) legendEntries.push({
|
|
153
|
+
key: "@",
|
|
154
|
+
label: "to insert a directive"
|
|
155
|
+
});
|
|
156
|
+
return /* @__PURE__ */ jsxs(EditorContext.Provider, {
|
|
157
|
+
value: { editor },
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ jsx(EditorContent, { editor }),
|
|
160
|
+
!hideLegend && /* @__PURE__ */ jsx(FieldLegend, { entries: legendEntries }),
|
|
161
|
+
/* @__PURE__ */ jsx(SuggestionMenu, {
|
|
162
|
+
editor,
|
|
163
|
+
char: "/",
|
|
164
|
+
pluginKey: "liquidEditorReferencePicker",
|
|
165
|
+
items: referenceItems,
|
|
166
|
+
children: (props) => /* @__PURE__ */ jsx(UnifiedReferencePicker, {
|
|
167
|
+
items: props.items,
|
|
168
|
+
selectedIndex: props.selectedIndex,
|
|
169
|
+
onSelect: props.onSelect,
|
|
170
|
+
query: props.query,
|
|
171
|
+
hasSecretsResolver,
|
|
172
|
+
inputFieldsCount: inputFields.length,
|
|
173
|
+
constantsCount: visibleConstants.length
|
|
174
|
+
})
|
|
175
|
+
}),
|
|
176
|
+
supportsOutput && /* @__PURE__ */ jsx(SuggestionMenu, {
|
|
177
|
+
editor,
|
|
178
|
+
char: "@",
|
|
179
|
+
pluginKey: "liquidEditorDirectivePicker",
|
|
180
|
+
items: directiveItems,
|
|
181
|
+
children: ({ items, selectedIndex, onSelect }) => /* @__PURE__ */ jsxs("div", {
|
|
182
|
+
className: "pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-56",
|
|
183
|
+
role: "listbox",
|
|
184
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
185
|
+
className: "pz:px-2 pz:pt-1 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground",
|
|
186
|
+
children: "Add output declaration"
|
|
187
|
+
}), items.map((item, index) => /* @__PURE__ */ jsx("button", {
|
|
188
|
+
type: "button",
|
|
189
|
+
role: "option",
|
|
190
|
+
"aria-selected": selectedIndex === index,
|
|
191
|
+
onClick: () => onSelect(item),
|
|
192
|
+
className: cn("pz:flex pz:w-full pz:items-center pz:rounded-sm pz:px-2 pz:py-1.5 pz:text-sm pz:text-left pz:cursor-pointer", selectedIndex === index ? "pz:bg-accent pz:text-accent-foreground" : "pz:hover:bg-accent pz:hover:text-accent-foreground"),
|
|
193
|
+
children: item.title
|
|
194
|
+
}, item.title))]
|
|
195
|
+
})
|
|
196
|
+
}),
|
|
197
|
+
chipTarget && editor && /* @__PURE__ */ jsx(ChipEditPopover, {
|
|
198
|
+
editor,
|
|
199
|
+
target: chipTarget,
|
|
200
|
+
onClose: () => setChipTarget(null)
|
|
201
|
+
})
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
//#endregion
|
|
207
|
+
export { LiquidEditor };
|
|
208
|
+
//# sourceMappingURL=LiquidEditor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiquidEditor.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/LiquidEditor.tsx"],"sourcesContent":["import {\n type PipesFieldDefinitionWithName,\n RECORD_FIELD_TYPES,\n type RecordFieldType,\n} from \"@pipe0/base\";\nimport type { EditorProps } from \"@tiptap/pm/view\";\nimport { EditorContent, EditorContext, useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { ConstantSuggestion, SecretSuggestion } from \"../../../types/field-props.js\";\nimport { FieldLegend, type LegendEntry } from \"../field-legend.js\";\nimport { SuggestionMenu } from \"../suggestion-menu/suggestion-menu.js\";\nimport type { SuggestionItem } from \"../suggestion-menu/suggestion-menu-types.js\";\nimport { type ChipHit, TagChipDecoration } from \"../tag-chip-decoration.js\";\nimport { ChipEditPopover, type ChipEditTarget } from \"./ChipEditPopover.js\";\nimport {\n buildReferenceItems,\n type ReferenceContext,\n UnifiedReferencePicker,\n} from \"./UnifiedReferencePicker.js\";\n\nexport type DirectiveKind = \"output\";\n\nconst SECRET_SEARCH_DEBOUNCE_MS = 150;\n\nexport interface LiquidEditorProps {\n value: string;\n onChange: (v: string) => void;\n inputFields: PipesFieldDefinitionWithName[];\n /**\n * Per-keystroke async searcher for secrets. Called from the `/` reference\n * picker as the user types. Calls are debounced and race-guarded — only\n * the response for the latest query is rendered.\n */\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n constantSuggestions?: ConstantSuggestion[];\n multiline?: boolean;\n /**\n * When true, the editor renders within `min-h`/`max-h` bounds. When\n * false, callers control the height via `className`. Default: true.\n */\n autoGrow?: boolean;\n directives?: DirectiveKind[];\n expectedFieldType?: RecordFieldType;\n placeholder?: string;\n className?: string;\n editorProps?: EditorProps;\n /**\n * Suppress the per-editor legend. Used by `key_value_list_input` which\n * renders a single legend below the entire list rather than per-cell.\n */\n hideLegend?: boolean;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/**\n * Reconciles single- and multi-line text into Tiptap-friendly HTML.\n * - Single-line: collapses whitespace runs containing newlines into a\n * single space and renders as one paragraph.\n * - Multi-line: paragraphs separated by blank lines (`\\n\\n+`); soft\n * breaks within a paragraph render as `<br>`. Leading spaces on each\n * line are preserved with ` ` so JSON-shaped payloads round-trip\n * through the editor.\n */\nfunction textToTiptapHTML(text: string, multiline: boolean): string {\n if (!multiline) {\n return `<p>${escapeHtml(text.replace(/\\s*\\n+\\s*/g, \" \"))}</p>`;\n }\n return escapeHtml(text)\n .split(/\\n\\n+/)\n .map((block) => {\n const lines = block.split(/\\n/);\n const htmlLines = lines\n .map((line) => line.replace(/^ +/, (spaces) => \" \".repeat(spaces.length)))\n .join(\"<br>\");\n return `<p>${htmlLines}</p>`;\n })\n .join(\"\");\n}\n\nconst OUTPUT_TEMPLATE = (fieldType: RecordFieldType): string => {\n if (fieldType === \"json\") {\n return `{% output FIELD_NAME, type: \"json\", schema: \"SCHEMA_NAME\", description: \"\" %}`;\n }\n return `{% output FIELD_NAME, type: \"${fieldType}\", description: \"\" %}`;\n};\n\n/**\n * Single editor surface for every form field that accepts Liquid tags.\n * Two triggers, two cognitive categories:\n *\n * - `/` opens a unified reference picker (Fields, Secrets, Constants).\n * Prefix syntax `/f/`, `/s/`, `/c/` filters to one source. Picking\n * emits the corresponding `{{ … }}` Liquid Output.\n *\n * - `@` opens a directives picker (only when `directives.length > 0`).\n * Today the only directive is `output`, which inserts a templated\n * `{% output FIELD_NAME, type: \"...\", description: \"\" %}` block.\n *\n * Chips render via the `TagChipDecoration` extension. Click or\n * Enter/Space on a chip mounts the contextual `ChipEditPopover`.\n *\n * Backwards compat: the persisted value is plain Liquid text,\n * byte-identical to what the legacy `TagEditor` / `TextPromptEditor`\n * produced. No engine, analyzer, or metadata changes.\n */\nexport function LiquidEditor({\n value,\n onChange,\n inputFields,\n searchSecrets,\n constantSuggestions,\n multiline = false,\n autoGrow = true,\n directives = [],\n expectedFieldType,\n placeholder,\n className,\n editorProps,\n hideLegend = false,\n}: LiquidEditorProps) {\n const blockSeparator = multiline ? \"\\n\" : \"\";\n const visibleConstants = constantSuggestions ?? [];\n const supportsOutput = directives.includes(\"output\");\n const hasSecretsResolver = !!searchSecrets;\n\n const [chipTarget, setChipTarget] = useState<ChipEditTarget | null>(null);\n\n const tagChipExtension = useMemo(\n () =>\n TagChipDecoration.configure({\n onChipClick: (hit: ChipHit, el: HTMLElement) => {\n setChipTarget({\n kind: hit.kind,\n raw: hit.raw,\n from: hit.from,\n to: hit.to,\n rect: el.getBoundingClientRect(),\n });\n },\n }),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({ hardBreak: !multiline ? false : undefined }),\n tagChipExtension,\n ],\n parseOptions: { preserveWhitespace: \"full\" },\n editorProps: {\n ...editorProps,\n attributes: {\n class: cn(\n \"pz:px-2.5 pz:py-1 pz:text-sm pz:outline-none pz:break-words\",\n multiline\n ? autoGrow\n ? \"pz:min-h-24 pz:max-h-96 pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:min-h-8\",\n className,\n ),\n ...(placeholder ? { \"data-placeholder\": placeholder } : {}),\n ...editorProps?.attributes,\n },\n handleKeyDown(view, event) {\n if (editorProps?.handleKeyDown?.(view, event)) return true;\n // Single-line: Enter must not split the document. Multi-line: let\n // StarterKit handle Enter so paragraphs and blocks behave normally.\n if (!multiline && event.key === \"Enter\") return true;\n return false;\n },\n },\n content: textToTiptapHTML(value || \"\", multiline),\n onUpdate({ editor }) {\n onChange(editor.getText({ blockSeparator }));\n },\n });\n\n // Sync the editor's document when `value` changes from outside (e.g.\n // form reset, programmatic setValue). `useEditor` only reads `content`\n // at mount; without this hook the visible UI drifts from form state.\n // The early-return short-circuits the loop that the editor's own\n // `onUpdate` would otherwise create.\n useEffect(() => {\n if (!editor) return;\n const current = editor.getText({ blockSeparator });\n if (current === (value ?? \"\")) return;\n editor.commands.setContent(textToTiptapHTML(value ?? \"\", multiline), false);\n }, [editor, value, multiline, blockSeparator]);\n\n const insertField = useCallback((name: string) => `{{ ${name} }}`, []);\n\n // Live-query state for secrets. The picker calls `referenceItems(query)` on\n // every keystroke; we debounce the underlying fetch and race-guard via\n // `latestQueryRef` so only the response for the most recent query lands.\n // `lastSecretsRef` carries the previous fetch's results forward so stale\n // calls render something sensible instead of an empty list.\n const lastSecretsRef = useRef<SecretSuggestion[]>([]);\n const latestQueryRef = useRef(\"\");\n\n const referenceItems = useCallback(\n ({ query }: { query: string }): Promise<SuggestionItem<ReferenceContext>[]> => {\n latestQueryRef.current = query;\n const myQuery = query;\n\n const buildWith = (secrets: SecretSuggestion[]) =>\n buildReferenceItems(\n myQuery,\n {\n inputFields,\n secretSuggestions: secrets,\n constantSuggestions: visibleConstants,\n },\n expectedFieldType,\n insertField,\n );\n\n if (!searchSecrets) {\n return Promise.resolve(buildWith([]));\n }\n\n return new Promise<SuggestionItem<ReferenceContext>[]>((resolve) => {\n setTimeout(async () => {\n if (latestQueryRef.current !== myQuery) {\n resolve(buildWith(lastSecretsRef.current));\n return;\n }\n try {\n const secrets = await searchSecrets(myQuery);\n if (latestQueryRef.current !== myQuery) {\n resolve(buildWith(lastSecretsRef.current));\n return;\n }\n lastSecretsRef.current = secrets;\n resolve(buildWith(secrets));\n } catch {\n resolve(buildWith(lastSecretsRef.current));\n }\n }, SECRET_SEARCH_DEBOUNCE_MS);\n });\n },\n [searchSecrets, inputFields, visibleConstants, expectedFieldType, insertField],\n );\n\n const directiveItems = useCallback(\n () =>\n RECORD_FIELD_TYPES.map<SuggestionItem>((fieldType) => ({\n title: `output: ${fieldType}`,\n keywords: [fieldType, \"output\"],\n onSelect: ({ editor: ed, range }) => {\n ed.chain().focus().insertContentAt(range, OUTPUT_TEMPLATE(fieldType)).run();\n },\n })),\n [],\n );\n\n const legendEntries: LegendEntry[] = [];\n legendEntries.push({ key: \"/\", label: \"to insert a reference\" });\n if (supportsOutput) legendEntries.push({ key: \"@\", label: \"to insert a directive\" });\n\n return (\n <EditorContext.Provider value={{ editor }}>\n <EditorContent editor={editor} />\n\n {!hideLegend && <FieldLegend entries={legendEntries} />}\n\n <SuggestionMenu\n editor={editor}\n char=\"/\"\n pluginKey=\"liquidEditorReferencePicker\"\n items={referenceItems}\n >\n {(props) => (\n <UnifiedReferencePicker\n items={props.items as SuggestionItem<ReferenceContext>[]}\n selectedIndex={props.selectedIndex}\n onSelect={props.onSelect as (item: SuggestionItem<ReferenceContext>) => void}\n query={props.query}\n hasSecretsResolver={hasSecretsResolver}\n inputFieldsCount={inputFields.length}\n constantsCount={visibleConstants.length}\n />\n )}\n </SuggestionMenu>\n\n {supportsOutput && (\n <SuggestionMenu\n editor={editor}\n char=\"@\"\n pluginKey=\"liquidEditorDirectivePicker\"\n items={directiveItems}\n >\n {({ items, selectedIndex, onSelect }) => (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-56\" role=\"listbox\">\n <div className=\"pz:px-2 pz:pt-1 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground\">\n Add output declaration\n </div>\n {items.map((item, index) => (\n <button\n key={item.title}\n type=\"button\"\n role=\"option\"\n aria-selected={selectedIndex === index}\n onClick={() => onSelect(item)}\n className={cn(\n \"pz:flex pz:w-full pz:items-center pz:rounded-sm pz:px-2 pz:py-1.5 pz:text-sm pz:text-left pz:cursor-pointer\",\n selectedIndex === index\n ? \"pz:bg-accent pz:text-accent-foreground\"\n : \"pz:hover:bg-accent pz:hover:text-accent-foreground\",\n )}\n >\n {item.title}\n </button>\n ))}\n </div>\n )}\n </SuggestionMenu>\n )}\n\n {chipTarget && editor && (\n <ChipEditPopover\n editor={editor}\n target={chipTarget}\n onClose={() => setChipTarget(null)}\n />\n )}\n </EditorContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Hash, Key } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/internal/LiquidEditor/UnifiedReferencePicker.tsx
|
|
5
|
+
const PREFIX_RE = /^([fsc])\/(.*)$/;
|
|
6
|
+
/**
|
|
7
|
+
* Parses a typed query into `(prefix, residual)`. Lets users filter
|
|
8
|
+
* directly to a single source: `f/email`, `s/STRIPE`, `c/REGION`.
|
|
9
|
+
* Without a prefix, all sources are searched.
|
|
10
|
+
*/
|
|
11
|
+
function parseQuery(query) {
|
|
12
|
+
const m = query.match(PREFIX_RE);
|
|
13
|
+
if (!m) return {
|
|
14
|
+
prefix: null,
|
|
15
|
+
residual: query
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
prefix: {
|
|
19
|
+
f: "field",
|
|
20
|
+
s: "secret",
|
|
21
|
+
c: "constant"
|
|
22
|
+
}[m[1]],
|
|
23
|
+
residual: m[2]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function score(haystack, needle) {
|
|
27
|
+
if (!needle) return 1;
|
|
28
|
+
const h = haystack.toLowerCase();
|
|
29
|
+
const n = needle.toLowerCase();
|
|
30
|
+
if (h === n) return 100;
|
|
31
|
+
if (h.startsWith(n)) return 50;
|
|
32
|
+
if (h.includes(n)) return 10;
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
function buildFieldItem(f, insertField) {
|
|
36
|
+
return {
|
|
37
|
+
title: f.resolvedName,
|
|
38
|
+
subtext: f.type,
|
|
39
|
+
keywords: [f.type],
|
|
40
|
+
context: { kind: "field" },
|
|
41
|
+
onSelect: ({ editor, range }) => {
|
|
42
|
+
editor.chain().focus().insertContentAt(range, insertField(f.resolvedName)).run();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function buildSecretItem(s) {
|
|
47
|
+
return {
|
|
48
|
+
title: s.label,
|
|
49
|
+
subtext: `${s.mask} · ${s.ownershipLevel}${s.providerHint ? ` · ${s.providerHint}` : ""}`,
|
|
50
|
+
keywords: [s.publicId, s.providerHint ?? ""],
|
|
51
|
+
context: { kind: "secret" },
|
|
52
|
+
onSelect: ({ editor, range }) => {
|
|
53
|
+
editor.chain().focus().insertContentAt(range, `{{ SECRETS.${s.publicId} }}`).run();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function buildConstantItem(c) {
|
|
58
|
+
return {
|
|
59
|
+
title: c.label,
|
|
60
|
+
subtext: c.ownershipLevel,
|
|
61
|
+
keywords: [c.publicId],
|
|
62
|
+
context: { kind: "constant" },
|
|
63
|
+
onSelect: ({ editor, range }) => {
|
|
64
|
+
editor.chain().focus().insertContentAt(range, `{{ CONSTANTS.${c.publicId} }}`).run();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Builds the suggestion list for a given query against the three sources.
|
|
70
|
+
* Behavior:
|
|
71
|
+
* - empty query → returns all items in source order (Fields, then
|
|
72
|
+
* Secrets, then Constants). Header rows are rendered separately by
|
|
73
|
+
* the picker UI — this function returns a flat list of items only.
|
|
74
|
+
* - non-empty query → ranks across all sources with a simple
|
|
75
|
+
* starts-with > includes scoring. Items with a zero score are
|
|
76
|
+
* dropped.
|
|
77
|
+
* - prefix syntax `f/`, `s/`, `c/` filters to a single source before
|
|
78
|
+
* scoring with the residual.
|
|
79
|
+
*/
|
|
80
|
+
function buildReferenceItems(query, sources, expectedFieldType, insertField) {
|
|
81
|
+
const { prefix, residual } = parseQuery(query);
|
|
82
|
+
const fieldItems = (expectedFieldType ? sources.inputFields.filter((f) => f.type === expectedFieldType) : sources.inputFields).map((f) => buildFieldItem(f, insertField));
|
|
83
|
+
const secretItems = sources.secretSuggestions.map(buildSecretItem);
|
|
84
|
+
const constantItems = sources.constantSuggestions.map(buildConstantItem);
|
|
85
|
+
const pool = prefix === "field" ? fieldItems : prefix === "secret" ? secretItems : prefix === "constant" ? constantItems : [
|
|
86
|
+
...fieldItems,
|
|
87
|
+
...secretItems,
|
|
88
|
+
...constantItems
|
|
89
|
+
];
|
|
90
|
+
if (!residual.trim()) return pool;
|
|
91
|
+
return pool.map((item) => {
|
|
92
|
+
const titleScore = score(item.title, residual);
|
|
93
|
+
const keywordScore = (item.keywords ?? []).reduce((best, kw) => Math.max(best, score(kw, residual)), 0);
|
|
94
|
+
const subtextScore = item.subtext ? score(item.subtext, residual) * .5 : 0;
|
|
95
|
+
return {
|
|
96
|
+
item,
|
|
97
|
+
total: Math.max(titleScore, keywordScore, subtextScore)
|
|
98
|
+
};
|
|
99
|
+
}).filter(({ total }) => total > 0).sort((a, b) => b.total - a.total).map(({ item }) => item);
|
|
100
|
+
}
|
|
101
|
+
function KindIcon({ kind }) {
|
|
102
|
+
if (kind === "field") return null;
|
|
103
|
+
if (kind === "secret") return /* @__PURE__ */ jsx(Key, {
|
|
104
|
+
className: "pz:size-3.5 pz:text-amber-700",
|
|
105
|
+
"aria-hidden": true
|
|
106
|
+
});
|
|
107
|
+
return /* @__PURE__ */ jsx(Hash, {
|
|
108
|
+
className: "pz:size-3.5 pz:text-violet-700",
|
|
109
|
+
"aria-hidden": true
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function SectionHeader({ children }) {
|
|
113
|
+
return /* @__PURE__ */ jsx("div", {
|
|
114
|
+
className: "pz:px-2 pz:pt-1.5 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground",
|
|
115
|
+
children
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function ItemRow({ item, active, onSelect }) {
|
|
119
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
120
|
+
type: "button",
|
|
121
|
+
role: "option",
|
|
122
|
+
"aria-selected": active,
|
|
123
|
+
onClick: () => onSelect(item),
|
|
124
|
+
className: ["pz:flex pz:w-full pz:items-center pz:gap-2 pz:rounded-sm pz:px-2 pz:py-1 pz:text-sm pz:text-left pz:cursor-pointer", active ? "pz:bg-accent pz:text-accent-foreground" : "pz:hover:bg-accent pz:hover:text-accent-foreground"].join(" "),
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ jsx(KindIcon, { kind: item.context?.kind ?? "field" }),
|
|
127
|
+
/* @__PURE__ */ jsx("span", {
|
|
128
|
+
className: "pz:truncate",
|
|
129
|
+
children: item.title
|
|
130
|
+
}),
|
|
131
|
+
item.subtext && /* @__PURE__ */ jsx("span", {
|
|
132
|
+
className: "pz:ml-auto pz:shrink-0 pz:truncate pz:text-xs pz:text-muted-foreground",
|
|
133
|
+
children: item.subtext
|
|
134
|
+
})
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Picker UI rendered inside the SuggestionMenu's children render-prop.
|
|
140
|
+
*
|
|
141
|
+
* - Empty query → sectioned view (Fields, Secrets, Constants).
|
|
142
|
+
* - Non-empty query → flat ranked list.
|
|
143
|
+
*
|
|
144
|
+
* The selected-index pointer from `SuggestionMenuRenderProps` always maps
|
|
145
|
+
* to the flat `items` order. Sectioned mode uses the same flat order but
|
|
146
|
+
* inserts headers between the boundaries, so highlight tracking still
|
|
147
|
+
* works without bespoke navigation.
|
|
148
|
+
*/
|
|
149
|
+
function UnifiedReferencePicker({ items, selectedIndex, onSelect, query, hasSecretsResolver, inputFieldsCount, constantsCount }) {
|
|
150
|
+
const { prefix, residual } = parseQuery(query);
|
|
151
|
+
if (!!residual.trim() || prefix !== null) {
|
|
152
|
+
if (items.length === 0) return /* @__PURE__ */ jsxs("div", {
|
|
153
|
+
className: "pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72",
|
|
154
|
+
role: "listbox",
|
|
155
|
+
children: [prefix && /* @__PURE__ */ jsx(SectionHeader, { children: prefix === "field" ? "Fields" : prefix === "secret" ? "Secrets" : "Constants" }), /* @__PURE__ */ jsx("div", {
|
|
156
|
+
className: "pz:px-2 pz:py-1.5 pz:text-sm pz:text-muted-foreground",
|
|
157
|
+
children: describeEmpty(prefix)
|
|
158
|
+
})]
|
|
159
|
+
});
|
|
160
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
161
|
+
className: "pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72",
|
|
162
|
+
role: "listbox",
|
|
163
|
+
children: [prefix && /* @__PURE__ */ jsx(SectionHeader, { children: prefix === "field" ? "Fields" : prefix === "secret" ? "Secrets" : "Constants" }), items.map((item, index) => /* @__PURE__ */ jsx(ItemRow, {
|
|
164
|
+
item,
|
|
165
|
+
active: selectedIndex === index,
|
|
166
|
+
onSelect
|
|
167
|
+
}, `${item.context?.kind}-${item.title}`))]
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const fieldItems = items.filter((it) => it.context?.kind === "field");
|
|
171
|
+
const secretItems = items.filter((it) => it.context?.kind === "secret");
|
|
172
|
+
const constantItems = items.filter((it) => it.context?.kind === "constant");
|
|
173
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
174
|
+
className: "pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72",
|
|
175
|
+
role: "listbox",
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsx(Section, {
|
|
178
|
+
label: "Fields",
|
|
179
|
+
kind: "field",
|
|
180
|
+
items: fieldItems,
|
|
181
|
+
startIndex: 0,
|
|
182
|
+
selectedIndex,
|
|
183
|
+
onSelect,
|
|
184
|
+
emptyHint: inputFieldsCount === 0 ? "No input fields available." : "No matching input fields."
|
|
185
|
+
}),
|
|
186
|
+
hasSecretsResolver && /* @__PURE__ */ jsx(Section, {
|
|
187
|
+
label: "Secrets",
|
|
188
|
+
kind: "secret",
|
|
189
|
+
items: secretItems,
|
|
190
|
+
startIndex: fieldItems.length,
|
|
191
|
+
selectedIndex,
|
|
192
|
+
onSelect,
|
|
193
|
+
emptyHint: "No matching secrets.",
|
|
194
|
+
helperHint: "Type /s/ to filter to secrets only."
|
|
195
|
+
}),
|
|
196
|
+
constantsCount > 0 && /* @__PURE__ */ jsx(Section, {
|
|
197
|
+
label: "Constants",
|
|
198
|
+
kind: "constant",
|
|
199
|
+
items: constantItems,
|
|
200
|
+
startIndex: fieldItems.length + secretItems.length,
|
|
201
|
+
selectedIndex,
|
|
202
|
+
onSelect,
|
|
203
|
+
emptyHint: "No matching constants."
|
|
204
|
+
})
|
|
205
|
+
]
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function Section({ label, kind, items, startIndex, selectedIndex, onSelect, emptyHint, helperHint }) {
|
|
209
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
210
|
+
className: "pz:flex pz:flex-col",
|
|
211
|
+
children: [/* @__PURE__ */ jsxs(SectionHeader, { children: [label, items.length > 0 && /* @__PURE__ */ jsxs("span", {
|
|
212
|
+
className: "pz:ml-1 pz:normal-case pz:tracking-normal",
|
|
213
|
+
children: [
|
|
214
|
+
"(",
|
|
215
|
+
items.length,
|
|
216
|
+
")"
|
|
217
|
+
]
|
|
218
|
+
})] }), items.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
219
|
+
className: "pz:px-2 pz:py-1 pz:text-xs pz:text-muted-foreground",
|
|
220
|
+
children: [emptyHint, helperHint && /* @__PURE__ */ jsx("span", {
|
|
221
|
+
className: "pz:block pz:opacity-70",
|
|
222
|
+
children: helperHint
|
|
223
|
+
})]
|
|
224
|
+
}) : items.map((item, i) => /* @__PURE__ */ jsx(ItemRow, {
|
|
225
|
+
item,
|
|
226
|
+
active: selectedIndex === startIndex + i,
|
|
227
|
+
onSelect
|
|
228
|
+
}, `${kind}-${item.title}`))]
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function describeEmpty(prefix) {
|
|
232
|
+
if (prefix === "secret") return "No matching secrets.";
|
|
233
|
+
if (prefix === "constant") return "No matching constants.";
|
|
234
|
+
if (prefix === "field") return "No matching fields.";
|
|
235
|
+
return "No matches.";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
export { UnifiedReferencePicker, buildReferenceItems };
|
|
240
|
+
//# sourceMappingURL=UnifiedReferencePicker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnifiedReferencePicker.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/UnifiedReferencePicker.tsx"],"sourcesContent":["import type { PipesFieldDefinitionWithName } from \"@pipe0/base\";\nimport { Hash, Key } from \"lucide-react\";\nimport type { ConstantSuggestion, SecretSuggestion } from \"../../../types/field-props.js\";\nimport type {\n SuggestionItem,\n SuggestionMenuRenderProps,\n} from \"../suggestion-menu/suggestion-menu-types.js\";\n\nexport type ReferenceKind = \"field\" | \"secret\" | \"constant\";\n\nexport interface ReferenceContext {\n kind: ReferenceKind;\n}\n\nexport interface ReferenceSources {\n inputFields: PipesFieldDefinitionWithName[];\n secretSuggestions: SecretSuggestion[];\n constantSuggestions: ConstantSuggestion[];\n}\n\nconst PREFIX_RE = /^([fsc])\\/(.*)$/;\n\n/**\n * Parses a typed query into `(prefix, residual)`. Lets users filter\n * directly to a single source: `f/email`, `s/STRIPE`, `c/REGION`.\n * Without a prefix, all sources are searched.\n */\nexport function parseQuery(query: string): {\n prefix: ReferenceKind | null;\n residual: string;\n} {\n const m = query.match(PREFIX_RE);\n if (!m) return { prefix: null, residual: query };\n const map = { f: \"field\", s: \"secret\", c: \"constant\" } as const;\n return { prefix: map[m[1] as \"f\" | \"s\" | \"c\"], residual: m[2] };\n}\n\nfunction score(haystack: string, needle: string): number {\n if (!needle) return 1;\n const h = haystack.toLowerCase();\n const n = needle.toLowerCase();\n if (h === n) return 100;\n if (h.startsWith(n)) return 50;\n if (h.includes(n)) return 10;\n return 0;\n}\n\nfunction buildFieldItem(\n f: PipesFieldDefinitionWithName,\n insertField: (name: string) => string,\n): SuggestionItem<ReferenceContext> {\n return {\n title: f.resolvedName,\n subtext: f.type,\n keywords: [f.type],\n context: { kind: \"field\" },\n onSelect: ({ editor, range }) => {\n editor.chain().focus().insertContentAt(range, insertField(f.resolvedName)).run();\n },\n };\n}\n\nfunction buildSecretItem(s: SecretSuggestion): SuggestionItem<ReferenceContext> {\n return {\n title: s.label,\n subtext: `${s.mask} · ${s.ownershipLevel}${s.providerHint ? ` · ${s.providerHint}` : \"\"}`,\n keywords: [s.publicId, s.providerHint ?? \"\"],\n context: { kind: \"secret\" },\n onSelect: ({ editor, range }) => {\n editor.chain().focus().insertContentAt(range, `{{ SECRETS.${s.publicId} }}`).run();\n },\n };\n}\n\nfunction buildConstantItem(c: ConstantSuggestion): SuggestionItem<ReferenceContext> {\n return {\n title: c.label,\n subtext: c.ownershipLevel,\n keywords: [c.publicId],\n context: { kind: \"constant\" },\n onSelect: ({ editor, range }) => {\n editor.chain().focus().insertContentAt(range, `{{ CONSTANTS.${c.publicId} }}`).run();\n },\n };\n}\n\n/**\n * Builds the suggestion list for a given query against the three sources.\n * Behavior:\n * - empty query → returns all items in source order (Fields, then\n * Secrets, then Constants). Header rows are rendered separately by\n * the picker UI — this function returns a flat list of items only.\n * - non-empty query → ranks across all sources with a simple\n * starts-with > includes scoring. Items with a zero score are\n * dropped.\n * - prefix syntax `f/`, `s/`, `c/` filters to a single source before\n * scoring with the residual.\n */\nexport function buildReferenceItems(\n query: string,\n sources: ReferenceSources,\n expectedFieldType: string | undefined,\n insertField: (name: string) => string,\n): SuggestionItem<ReferenceContext>[] {\n const { prefix, residual } = parseQuery(query);\n\n const fieldsAll = expectedFieldType\n ? sources.inputFields.filter((f) => f.type === expectedFieldType)\n : sources.inputFields;\n\n const fieldItems = fieldsAll.map((f) => buildFieldItem(f, insertField));\n const secretItems = sources.secretSuggestions.map(buildSecretItem);\n const constantItems = sources.constantSuggestions.map(buildConstantItem);\n\n const pool: SuggestionItem<ReferenceContext>[] =\n prefix === \"field\"\n ? fieldItems\n : prefix === \"secret\"\n ? secretItems\n : prefix === \"constant\"\n ? constantItems\n : [...fieldItems, ...secretItems, ...constantItems];\n\n if (!residual.trim()) return pool;\n\n return pool\n .map((item) => {\n const titleScore = score(item.title, residual);\n const keywordScore = (item.keywords ?? []).reduce(\n (best, kw) => Math.max(best, score(kw, residual)),\n 0,\n );\n const subtextScore = item.subtext ? score(item.subtext, residual) * 0.5 : 0;\n const total = Math.max(titleScore, keywordScore, subtextScore);\n return { item, total };\n })\n .filter(({ total }) => total > 0)\n .sort((a, b) => b.total - a.total)\n .map(({ item }) => item);\n}\n\nfunction KindIcon({ kind }: { kind: ReferenceKind }) {\n // Fields are the default category and don't need a marker — the section\n // header and the type column on the right convey the kind.\n if (kind === \"field\") return null;\n if (kind === \"secret\") return <Key className=\"pz:size-3.5 pz:text-amber-700\" aria-hidden />;\n return <Hash className=\"pz:size-3.5 pz:text-violet-700\" aria-hidden />;\n}\n\nfunction SectionHeader({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"pz:px-2 pz:pt-1.5 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground\">\n {children}\n </div>\n );\n}\n\nfunction ItemRow({\n item,\n active,\n onSelect,\n}: {\n item: SuggestionItem<ReferenceContext>;\n active: boolean;\n onSelect: (item: SuggestionItem<ReferenceContext>) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n onClick={() => onSelect(item)}\n className={[\n \"pz:flex pz:w-full pz:items-center pz:gap-2 pz:rounded-sm pz:px-2 pz:py-1 pz:text-sm pz:text-left pz:cursor-pointer\",\n active\n ? \"pz:bg-accent pz:text-accent-foreground\"\n : \"pz:hover:bg-accent pz:hover:text-accent-foreground\",\n ].join(\" \")}\n >\n <KindIcon kind={item.context?.kind ?? \"field\"} />\n <span className=\"pz:truncate\">{item.title}</span>\n {item.subtext && (\n <span className=\"pz:ml-auto pz:shrink-0 pz:truncate pz:text-xs pz:text-muted-foreground\">\n {item.subtext}\n </span>\n )}\n </button>\n );\n}\n\n/**\n * Picker UI rendered inside the SuggestionMenu's children render-prop.\n *\n * - Empty query → sectioned view (Fields, Secrets, Constants).\n * - Non-empty query → flat ranked list.\n *\n * The selected-index pointer from `SuggestionMenuRenderProps` always maps\n * to the flat `items` order. Sectioned mode uses the same flat order but\n * inserts headers between the boundaries, so highlight tracking still\n * works without bespoke navigation.\n */\nexport function UnifiedReferencePicker({\n items,\n selectedIndex,\n onSelect,\n query,\n hasSecretsResolver,\n inputFieldsCount,\n constantsCount,\n}: SuggestionMenuRenderProps<ReferenceContext> & {\n query: string;\n hasSecretsResolver: boolean;\n inputFieldsCount: number;\n constantsCount: number;\n}) {\n const { prefix, residual } = parseQuery(query);\n const isFlat = !!residual.trim() || prefix !== null;\n\n if (isFlat) {\n if (items.length === 0) {\n return (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72\" role=\"listbox\">\n {prefix && (\n <SectionHeader>\n {prefix === \"field\" ? \"Fields\" : prefix === \"secret\" ? \"Secrets\" : \"Constants\"}\n </SectionHeader>\n )}\n <div className=\"pz:px-2 pz:py-1.5 pz:text-sm pz:text-muted-foreground\">\n {describeEmpty(prefix)}\n </div>\n </div>\n );\n }\n return (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72\" role=\"listbox\">\n {prefix && (\n <SectionHeader>\n {prefix === \"field\" ? \"Fields\" : prefix === \"secret\" ? \"Secrets\" : \"Constants\"}\n </SectionHeader>\n )}\n {items.map((item, index) => (\n <ItemRow\n key={`${item.context?.kind}-${item.title}`}\n item={item}\n active={selectedIndex === index}\n onSelect={onSelect}\n />\n ))}\n </div>\n );\n }\n\n // Sectioned view — always render Fields and Secrets headers in fixed\n // order, with empty-state hints when a section has no items. Constants\n // only appear when there are any to show.\n //\n // The selectedIndex still maps to the flat `items` order returned by\n // `buildReferenceItems` (Fields → Secrets → Constants).\n const fieldItems = items.filter((it) => it.context?.kind === \"field\");\n const secretItems = items.filter((it) => it.context?.kind === \"secret\");\n const constantItems = items.filter((it) => it.context?.kind === \"constant\");\n\n return (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-72\" role=\"listbox\">\n <Section\n label=\"Fields\"\n kind=\"field\"\n items={fieldItems}\n startIndex={0}\n selectedIndex={selectedIndex}\n onSelect={onSelect}\n emptyHint={\n inputFieldsCount === 0\n ? \"No input fields available.\"\n : \"No matching input fields.\"\n }\n />\n {hasSecretsResolver && (\n <Section\n label=\"Secrets\"\n kind=\"secret\"\n items={secretItems}\n startIndex={fieldItems.length}\n selectedIndex={selectedIndex}\n onSelect={onSelect}\n emptyHint=\"No matching secrets.\"\n helperHint=\"Type /s/ to filter to secrets only.\"\n />\n )}\n {constantsCount > 0 && (\n <Section\n label=\"Constants\"\n kind=\"constant\"\n items={constantItems}\n startIndex={fieldItems.length + secretItems.length}\n selectedIndex={selectedIndex}\n onSelect={onSelect}\n emptyHint=\"No matching constants.\"\n />\n )}\n </div>\n );\n}\n\nfunction Section({\n label,\n kind,\n items,\n startIndex,\n selectedIndex,\n onSelect,\n emptyHint,\n helperHint,\n}: {\n label: string;\n kind: ReferenceKind;\n items: SuggestionItem<ReferenceContext>[];\n startIndex: number;\n selectedIndex?: number;\n onSelect: (item: SuggestionItem<ReferenceContext>) => void;\n emptyHint: string;\n helperHint?: string;\n}) {\n return (\n <div className=\"pz:flex pz:flex-col\">\n <SectionHeader>\n {label}\n {items.length > 0 && (\n <span className=\"pz:ml-1 pz:normal-case pz:tracking-normal\">({items.length})</span>\n )}\n </SectionHeader>\n {items.length === 0 ? (\n <div className=\"pz:px-2 pz:py-1 pz:text-xs pz:text-muted-foreground\">\n {emptyHint}\n {helperHint && <span className=\"pz:block pz:opacity-70\">{helperHint}</span>}\n </div>\n ) : (\n items.map((item, i) => (\n <ItemRow\n key={`${kind}-${item.title}`}\n item={item}\n active={selectedIndex === startIndex + i}\n onSelect={onSelect}\n />\n ))\n )}\n </div>\n );\n}\n\nfunction describeEmpty(prefix: ReferenceKind | null): string {\n if (prefix === \"secret\") return \"No matching secrets.\";\n if (prefix === \"constant\") return \"No matching constants.\";\n if (prefix === \"field\") return \"No matching fields.\";\n return \"No matches.\";\n}\n"],"mappings":"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"}
|