@phis/ui 0.4.2 → 0.4.4
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/components/cms/phi-cms-layout-renderer.js +4 -3
- package/components/cms/phi-cms-page-render-scope.d.ts +4 -5
- package/components/cms/phi-cms-page-render-scope.js +43 -22
- package/components/cms/phi-cms-render-diagnostic-client.js +7 -3
- package/components/cms/phi-cms-render-error-boundary.js +2 -1
- package/components/controls/phi-anchor-nav-control.js +4 -1
- package/components/controls/phi-background-control.js +21 -6
- package/components/controls/phi-bullet-list-control.d.ts +7 -2
- package/components/controls/phi-bullet-list-control.js +35 -5
- package/components/controls/phi-color-control.js +4 -2
- package/components/controls/phi-drawer-control-adapter.js +3 -2
- package/components/controls/phi-inline-text-editor.js +7 -1
- package/components/controls/phi-length-control.js +1 -1
- package/components/controls/phi-ribbon-control.d.ts +38 -0
- package/components/controls/phi-ribbon-control.js +57 -0
- package/components/controls/phi-ribbon-wrap-control.d.ts +26 -0
- package/components/controls/phi-ribbon-wrap-control.js +25 -0
- package/components/controls/phi-select-control.js +5 -2
- package/components/controls/phi-series-chart-control.d.ts +48 -0
- package/components/controls/phi-series-chart-control.js +82 -0
- package/components/controls/phi-table-control.d.ts +3 -0
- package/components/controls/phi-table-control.js +13 -1
- package/components/controls/phi-text-control.js +57 -3
- package/components/controls/phi-tree-control.js +4 -4
- package/components/controls/phi-truncated-hover-text.d.ts +15 -0
- package/components/controls/phi-truncated-hover-text.js +25 -0
- package/components/forms/link-target-form-control.d.ts +1 -1
- package/components/forms/link-target-form-control.js +2 -45
- package/components/forms/phi-form-widget-frame.js +4 -2
- package/components/forms/shared-form-provider-registry.js +1 -4
- package/components/layouts/clients/phi-three-column-layout-client.js +10 -1
- package/components/media/asset-collection-runtime.js +6 -16
- package/components/media/media-font-metrics.d.ts +3 -0
- package/components/media/media-font-metrics.js +43 -0
- package/components/media/phi-area-upload-widget.js +53 -97
- package/components/media/phi-image-preview-data.d.ts +13 -0
- package/components/media/phi-image-preview-data.js +184 -9
- package/components/media/phi-media-picker-binding.js +16 -13
- package/components/media/phi-media-upload.d.ts +15 -8
- package/components/media/phi-media-upload.js +18 -9
- package/components/media/phi-site-font-assets.js +7 -8
- package/components/navigation/phi-link.js +6 -1
- package/components/overlays/phi-overlay-container-client.js +16 -1
- package/components/regions/clients/cms-region-container-client.js +6 -1
- package/components/regions/phi-cms-region-container.js +3 -0
- package/components/regions/phi-cms-region-shell.d.ts +12 -1
- package/components/regions/phi-cms-region-shell.js +81 -19
- package/components/regions/presets/phi-settings-page-shell-tree.js +48 -1
- package/components/root/phi-config-provider.d.ts +13 -0
- package/components/root/phi-config-provider.js +12 -1
- package/components/root/phi-root-background.d.ts +7 -0
- package/components/root/phi-root-background.js +20 -1
- package/components/root/phi-root-theme-resolver.js +3 -0
- package/components/root/phi-shell-chrome-overlay.d.ts +12 -1
- package/components/root/phi-shell-chrome-overlay.js +19 -3
- package/components/runtime/runtime-controller-materialization.js +12 -1
- package/components/shell/phi-antd-icon.d.ts +1 -0
- package/components/shell/phi-antd-icon.js +3 -0
- package/components/shell/use-phi-shell-sticky-top.js +61 -16
- package/components/state/scoped-state-store.js +20 -3
- package/components/surface/phi-surface-tone.d.ts +13 -0
- package/components/surface/phi-surface-tone.js +21 -0
- package/components/tables/client/phi-table-binding.d.ts +2 -1
- package/components/tables/client/phi-table-binding.js +45 -21
- package/components/trees/client/phi-tree-binding.js +19 -11
- package/components/widgets/client/bullet-list-entries-editor.d.ts +26 -0
- package/components/widgets/client/bullet-list-entries-editor.js +109 -0
- package/components/widgets/client/html-editor.js +1 -1
- package/components/widgets/client/shared/use-page-reference-options.d.ts +17 -0
- package/components/widgets/client/shared/use-page-reference-options.js +57 -0
- package/components/widgets/config/background.d.ts +32 -1
- package/components/widgets/config/background.js +41 -2
- package/components/widgets/config/choice-shared.js +12 -13
- package/components/widgets/config/command-buttons.d.ts +5 -1
- package/components/widgets/config/command-buttons.js +38 -81
- package/components/widgets/config/control-signal-config.d.ts +3 -1
- package/components/widgets/config/control-signal-config.js +19 -17
- package/components/widgets/config/image-source-parser.d.ts +1 -0
- package/components/widgets/config/image-source-parser.js +7 -8
- package/components/widgets/config/mask.d.ts +6 -1
- package/components/widgets/config/mask.js +24 -1
- package/components/widgets/config/parser-primitives.js +72 -0
- package/components/widgets/config/stack-tabs.d.ts +1 -1
- package/components/widgets/config/stack-tabs.js +2 -3
- package/components/widgets/config/strict-config-reader.d.ts +40 -0
- package/components/widgets/config/strict-config-reader.js +174 -0
- package/components/widgets/label-sets/background.js +2 -0
- package/components/widgets/label-sets/effects.js +2 -0
- package/components/widgets/label-types/background.d.ts +1 -0
- package/components/widgets/label-types/background.js +1 -0
- package/components/widgets/label-types/effects.d.ts +1 -0
- package/components/widgets/label-types/effects.js +1 -0
- package/components/widgets/navigation-descriptor-resolver.server.js +20 -8
- package/components/widgets/shared/bullet-list-vocabulary.d.ts +27 -1
- package/components/widgets/shared/bullet-list-vocabulary.js +24 -4
- package/components/widgets/shared/card-body-client.d.ts +18 -4
- package/components/widgets/shared/card-body-client.js +126 -26
- package/components/widgets/shared/card-vocabulary.d.ts +31 -4
- package/components/widgets/shared/card-vocabulary.js +35 -2
- package/components/widgets/shared/markdown-body-client.js +39 -10
- package/components/widgets/signals/control-signal-capabilities.d.ts +0 -18
- package/components/widgets/signals/control-signal-capabilities.js +10 -22
- package/components/workspace/catalog-store.d.ts +4 -3
- package/components/workspace/catalog-store.js +6 -5
- package/gateway/dashboard-cards-route.js +1 -0
- package/gateway/internal-references.d.ts +6 -1
- package/gateway/internal-references.js +48 -23
- package/gateway/site-cms-write-validation.d.ts +9 -0
- package/gateway/site-cms-write-validation.js +78 -0
- package/gateway/site-proxy.js +19 -3
- package/helpers/cms-container-chrome.js +6 -1
- package/helpers/locale.d.ts +8 -0
- package/helpers/locale.js +18 -0
- package/helpers/renderable-block-serialization.js +1 -1
- package/helpers/shell-region-style.js +2 -1
- package/helpers/surface-style.d.ts +12 -1
- package/helpers/surface-style.js +28 -2
- package/module-dashboard-cards.d.ts +1 -1
- package/module-dashboard-cards.js +1 -1
- package/next/config.d.mts +3 -0
- package/next/config.mjs +28 -1
- package/package.json +2 -2
- package/plugins/runtime/phi-slot-child-viewport-effects-observer.js +5 -1
- package/plugins/runtime-modules/accounting/presets.d.ts +9 -0
- package/plugins/runtime-modules/accounting/presets.js +37 -0
- package/plugins/runtime-modules/accounting/server.d.ts +1 -4
- package/plugins/runtime-modules/accounting/server.js +4 -7
- package/plugins/runtime-modules/app/presets.d.ts +18 -0
- package/plugins/runtime-modules/app/presets.js +67 -0
- package/plugins/runtime-modules/app/server.d.ts +1 -4
- package/plugins/runtime-modules/app/server.js +4 -7
- package/plugins/runtime-modules/area-definitions.d.ts +0 -42
- package/plugins/runtime-modules/area-definitions.js +3 -8
- package/plugins/runtime-modules/asset/controller/runtime.js +2 -2
- package/plugins/runtime-modules/asset/services/collection.js +9 -1
- package/plugins/runtime-modules/asset/services/options.js +2 -2
- package/plugins/runtime-modules/builder/area-settings-answer.js +2 -1
- package/plugins/runtime-modules/builder/authoring-canvas.js +6 -6
- package/plugins/runtime-modules/builder/cards.js +3 -5
- package/plugins/runtime-modules/builder/clients/builder-region-overrides.js +3 -3
- package/plugins/runtime-modules/builder/clients/canvas-widget.js +15 -54
- package/plugins/runtime-modules/builder/clients/inspector-config-field.d.ts +4 -1
- package/plugins/runtime-modules/builder/clients/inspector-config-field.js +25 -35
- package/plugins/runtime-modules/builder/clients/inspector-link-target-field.js +1 -1
- package/plugins/runtime-modules/builder/clients/inspector-section-widget.js +8 -8
- package/plugins/runtime-modules/builder/clients/inspector-title.js +6 -6
- package/plugins/runtime-modules/builder/clients/layout-inspector.d.ts +1 -1
- package/plugins/runtime-modules/builder/clients/layout-inspector.js +11 -25
- package/plugins/runtime-modules/builder/clients/layout-scaffold-overlays.js +10 -5
- package/plugins/runtime-modules/builder/clients/mode-switch.js +1 -1
- package/plugins/runtime-modules/builder/clients/pages-header.js +11 -11
- package/plugins/runtime-modules/builder/clients/pages-workspace.js +1 -1
- package/plugins/runtime-modules/builder/clients/region-visibility-fields.js +1 -1
- package/plugins/runtime-modules/builder/clients/runtime-module-authoring-boundary.js +1 -1
- package/plugins/runtime-modules/builder/clients/shells-workspace.js +15 -31
- package/plugins/runtime-modules/builder/clients/structure-canvas.js +1 -1
- package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.d.ts +26 -0
- package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.js +36 -0
- package/plugins/runtime-modules/builder/clients/widget-effects-editor.js +1 -1
- package/plugins/runtime-modules/builder/clients/widget-inspector.js +1 -0
- package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +2 -2
- package/plugins/runtime-modules/builder/cms-instance-allocator.js +8 -28
- package/plugins/runtime-modules/builder/controller/client.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/definition.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/definition.js +0 -8
- package/plugins/runtime-modules/builder/controller/draft-command-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/draft-command-controller.js +11 -30
- package/plugins/runtime-modules/builder/controller/draft-status-controller.js +15 -2
- package/plugins/runtime-modules/builder/controller/inspector-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/inspector-controller.js +4 -7
- package/plugins/runtime-modules/builder/controller/page-controller.d.ts +1 -2
- package/plugins/runtime-modules/builder/controller/page-controller.js +16 -68
- package/plugins/runtime-modules/builder/controller/server-definition.d.ts +0 -15
- package/plugins/runtime-modules/builder/controller/signal-wiring-controller.d.ts +2 -5
- package/plugins/runtime-modules/builder/controller/signal-wiring-controller.js +6 -50
- package/plugins/runtime-modules/builder/controller/workspace-controller.d.ts +2 -3
- package/plugins/runtime-modules/builder/controller/workspace-controller.js +89 -153
- package/plugins/runtime-modules/builder/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/builder/data-providers.js +1 -0
- package/plugins/runtime-modules/builder/definition.d.ts +1 -0
- package/plugins/runtime-modules/builder/developer-workspace-store.d.ts +64 -30
- package/plugins/runtime-modules/builder/developer-workspace-store.js +255 -61
- package/plugins/runtime-modules/builder/edit-scaffold-drawer.js +4 -3
- package/plugins/runtime-modules/builder/history.d.ts +3 -1
- package/plugins/runtime-modules/builder/options-providers.js +3 -2
- package/plugins/runtime-modules/builder/page-catalog-client.js +19 -7
- package/plugins/runtime-modules/builder/page-meta-form.js +1 -0
- package/plugins/runtime-modules/builder/page-references-provider.js +1 -1
- package/plugins/runtime-modules/builder/persistence.js +33 -69
- package/plugins/runtime-modules/builder/public-route-collisions.d.ts +2 -2
- package/plugins/runtime-modules/builder/public-route-collisions.js +6 -19
- package/plugins/runtime-modules/builder/render-root-node-preview.server.js +20 -3
- package/plugins/runtime-modules/builder/render-root-node-scaffold.js +28 -18
- package/plugins/runtime-modules/builder/runtime-module-selection.d.ts +2 -12
- package/plugins/runtime-modules/builder/runtime-module-selection.js +16 -42
- package/plugins/runtime-modules/builder/services/navigation-table.js +9 -15
- package/plugins/runtime-modules/builder/services/page-source-tree.js +8 -8
- package/plugins/runtime-modules/builder/services/runtime-modules-table.js +10 -10
- package/plugins/runtime-modules/builder/services/signal-routes-table.js +3 -3
- package/plugins/runtime-modules/builder/signal-route-selection.d.ts +1 -2
- package/plugins/runtime-modules/builder/signal-route-selection.js +2 -2
- package/plugins/runtime-modules/builder/signal-wiring-options.js +3 -2
- package/plugins/runtime-modules/builder/structure-dnd.js +8 -61
- package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +17 -10
- package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +27 -22
- package/plugins/runtime-modules/builder/workspace-catalog-actions.d.ts +55 -0
- package/plugins/runtime-modules/builder/workspace-catalog-actions.js +142 -0
- package/plugins/runtime-modules/client-authoring-module.d.ts +8 -1
- package/plugins/runtime-modules/client-authoring-module.js +13 -3
- package/plugins/runtime-modules/client-manifests/common.js +1 -1
- package/plugins/runtime-modules/{runtime-calendar-adapters.js → core/calendar-adapters.js} +2 -2
- package/plugins/runtime-modules/{client-calendar-adapters/core.js → core/client-calendar-adapters.js} +1 -1
- package/plugins/runtime-modules/core/content-entries/table.js +1 -1
- package/plugins/runtime-modules/core/data-providers.d.ts +3 -0
- package/plugins/runtime-modules/core/data-providers.js +2 -1
- package/plugins/runtime-modules/core/definition.d.ts +3 -0
- package/plugins/runtime-modules/core/definition.js +1 -1
- package/plugins/runtime-modules/core/messaging/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/core/messaging/data-providers.js +1 -0
- package/plugins/runtime-modules/core/messaging/thread-inbox-table.js +1 -1
- package/plugins/runtime-modules/core/server.js +1 -1
- package/plugins/runtime-modules/core/themes.d.ts +44 -0
- package/plugins/runtime-modules/core/themes.js +12 -0
- package/plugins/runtime-modules/core/widgets/brand/client.d.ts +12 -3
- package/plugins/runtime-modules/core/widgets/brand/client.js +3 -11
- package/plugins/runtime-modules/core/widgets/brand/home.d.ts +15 -0
- package/plugins/runtime-modules/core/widgets/brand/home.js +18 -0
- package/plugins/runtime-modules/core/widgets/brand/plugin.js +3 -2
- package/plugins/runtime-modules/core/widgets/brand/server.d.ts +2 -2
- package/plugins/runtime-modules/core/widgets/brand/server.js +2 -2
- package/plugins/runtime-modules/core/widgets/card/collection-view-binding.js +25 -9
- package/plugins/runtime-modules/core/widgets/card/config.d.ts +301 -254
- package/plugins/runtime-modules/core/widgets/card/config.js +68 -3
- package/plugins/runtime-modules/core/widgets/card/editor.js +41 -4
- package/plugins/runtime-modules/core/widgets/card/server.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/card/server.js +32 -3
- package/plugins/runtime-modules/core/widgets/collection-view/asset-binding.js +7 -6
- package/plugins/runtime-modules/core/widgets/collection-view/config.js +9 -2
- package/plugins/runtime-modules/core/widgets/description/client.js +3 -3
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +2 -25
- package/plugins/runtime-modules/core/widgets/description/editor.js +7 -63
- package/plugins/runtime-modules/core/widgets/description/server.js +3 -2
- package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +2 -25
- package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +2 -25
- package/plugins/runtime-modules/core/widgets/header-navigation/client.js +2 -2
- package/plugins/runtime-modules/core/widgets/html/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/image/config.js +2 -2
- package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +320 -2
- package/plugins/runtime-modules/core/widgets/markdown/config.js +18 -4
- package/plugins/runtime-modules/core/widgets/markdown/editor.js +11 -4
- package/plugins/runtime-modules/core/widgets/markdown-toc/client.js +6 -1
- package/plugins/runtime-modules/core/widgets/markdown-toc/config.d.ts +14 -0
- package/plugins/runtime-modules/core/widgets/markdown-toc/config.js +14 -2
- package/plugins/runtime-modules/core/widgets/quick-links/authoring.js +7 -2
- package/plugins/runtime-modules/core/widgets/quick-links/client.js +2 -2
- package/plugins/runtime-modules/core/widgets/quick-links/items.d.ts +0 -2
- package/plugins/runtime-modules/core/widgets/quick-links/items.js +0 -15
- package/plugins/runtime-modules/core/widgets/result/config.d.ts +5 -25
- package/plugins/runtime-modules/core/widgets/result/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/result/server.js +25 -19
- package/plugins/runtime-modules/core/widgets/sidebar-navigation/authoring.js +1 -1
- package/plugins/runtime-modules/core/widgets/sidebar-navigation/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/simple-text/client.js +8 -3
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +2 -25
- package/plugins/runtime-modules/core/widgets/simple-text/editor.js +2 -2
- package/plugins/runtime-modules/core/widgets/slot-upload/client.js +11 -2
- package/plugins/runtime-modules/core/widgets/table/client.js +8 -4
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +6 -83
- package/plugins/runtime-modules/core/widgets/table/config.js +302 -452
- package/plugins/runtime-modules/core/widgets/tree/config.js +5 -2
- package/plugins/runtime-modules/dashboard/card-rows.d.ts +7 -0
- package/plugins/runtime-modules/dashboard/card-rows.js +87 -0
- package/plugins/runtime-modules/dashboard/clients/dashboard-card-view.js +32 -12
- package/plugins/runtime-modules/dashboard/services/collection.js +17 -7
- package/plugins/runtime-modules/dashboard/trees/phi-default-builder-dashboard-page-tree.js +5 -40
- package/plugins/runtime-modules/groups/data-providers.d.ts +2 -0
- package/plugins/runtime-modules/groups/data-providers.js +3 -3
- package/plugins/runtime-modules/groups/definition.d.ts +2 -0
- package/plugins/runtime-modules/localization/data-providers.d.ts +3 -0
- package/plugins/runtime-modules/localization/data-providers.js +2 -0
- package/plugins/runtime-modules/localization/definition.d.ts +3 -0
- package/plugins/runtime-modules/localization/services/table.js +3 -7
- package/plugins/runtime-modules/observability/data-providers.d.ts +1 -0
- package/plugins/runtime-modules/observability/data-providers.js +1 -0
- package/plugins/runtime-modules/observability/definition.d.ts +1 -0
- package/plugins/runtime-modules/observability/module.d.ts +1 -0
- package/plugins/runtime-modules/observability/services/table.js +1 -1
- package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +2 -105
- package/plugins/runtime-modules/public/presets.d.ts +115 -0
- package/plugins/runtime-modules/{area-base-presets.js → public/presets.js} +19 -119
- package/plugins/runtime-modules/public/server.d.ts +1 -4
- package/plugins/runtime-modules/public/server.js +4 -7
- package/plugins/runtime-modules/public/trees/phi-default-pub-error-page-tree.js +7 -8
- package/plugins/runtime-modules/public-base-page-references.d.ts +1 -1
- package/plugins/runtime-modules/public-base-page-references.js +1 -1
- package/plugins/runtime-modules/revisions/controller/client.js +11 -11
- package/plugins/runtime-modules/revisions/services/table.js +3 -3
- package/plugins/runtime-modules/theme/trees/phi-default-builder-theme-page-tree.js +22 -0
- package/plugins/runtime-modules/theme/widgets/brand-controls/client.d.ts +2 -1
- package/plugins/runtime-modules/theme/widgets/brand-controls/client.js +111 -72
- package/plugins/runtime-modules/theme/widgets/brand-controls/config.d.ts +2 -1
- package/plugins/runtime-modules/theme/widgets/brand-controls/config.js +28 -31
- package/plugins/runtime-modules/theme/widgets/brand-controls/plugin.js +1 -1
- package/plugins/runtime-modules/theme-descriptors.js +1 -1
- package/plugins/runtime-modules/user-management/data-providers.d.ts +2 -0
- package/plugins/runtime-modules/user-management/data-providers.js +1 -0
- package/plugins/runtime-modules/user-management/definition.d.ts +2 -0
- package/server-helpers/cms-link-targets.js +6 -0
- package/styles/control-shape.css +11 -11
- package/styles/controls.css +67 -5
- package/styles/layout.css +61 -9
- package/styles/shell.css +73 -0
- package/theme/phi-antd-token-resolver.js +20 -1
- package/theme/phi-theme-tokens.d.ts +1 -1
- package/theme/phi-theme-tokens.js +1 -0
- package/theme/phi-theme.d.ts +5 -0
- package/theme/phi-theme.js +21 -0
- package/theme/phi-tokens.d.ts +16 -15
- package/theme/phi-tokens.js +16 -15
- package/types/cms-config.js +142 -185
- package/types/cms-plugins.d.ts +6 -11
- package/types/core-widget-placements.d.ts +14 -3
- package/types/dashboard-cards.d.ts +48 -4
- package/types/dashboard-cards.js +6 -0
- package/types/media.d.ts +0 -3
- package/types/renderable-block.d.ts +6 -1
- package/types/site-theme.d.ts +10 -2
- package/types/table-widget.d.ts +9 -0
- package/types/table-widget.js +20 -0
- package/types.d.ts +1 -1
- package/widget-config.d.ts +2 -0
- package/widget-config.js +6 -0
- package/plugins/runtime-modules/area-base-presets.d.ts +0 -139
- /package/plugins/runtime-modules/{runtime-calendar-adapters.d.ts → core/calendar-adapters.d.ts} +0 -0
- /package/plugins/runtime-modules/{client-calendar-adapters/core.d.ts → core/client-calendar-adapters.d.ts} +0 -0
|
@@ -39,7 +39,18 @@ export function materializePhiWidgetRuntimeControllerSettings({ widget, tree, ow
|
|
|
39
39
|
if (!plugin.requiredRuntimeControllers) {
|
|
40
40
|
return [];
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
/*
|
|
43
|
+
* A Widget whose config cannot be read asks for no Controller. It is not rendered either: the renderer
|
|
44
|
+
* meets the same error in the Widget's own place, leaves it out of a live page and shows it in the
|
|
45
|
+
* Builder. Thrown here, outside any block, it took the whole page with it.
|
|
46
|
+
*/
|
|
47
|
+
let config;
|
|
48
|
+
try {
|
|
49
|
+
config = plugin.parseConfig(widget.config);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
43
54
|
const settingsByKey = new Map();
|
|
44
55
|
for (const requirement of plugin.requiredRuntimeControllers({ widget, tree, config })) {
|
|
45
56
|
const setting = {
|
|
@@ -17,6 +17,7 @@ declare const PHI_ANTD_ICON_LOADERS: {
|
|
|
17
17
|
readonly CalendarOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CalendarOutlined")>;
|
|
18
18
|
readonly CheckOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CheckOutlined")>;
|
|
19
19
|
readonly CloseOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloseOutlined")>;
|
|
20
|
+
readonly CloudDownloadOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloudDownloadOutlined")>;
|
|
20
21
|
readonly CloudUploadOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CloudUploadOutlined")>;
|
|
21
22
|
readonly ClusterOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/ClusterOutlined")>;
|
|
22
23
|
readonly CodeOutlined: () => Promise<typeof import("@ant-design/icons-svg/es/asn/CodeOutlined")>;
|
|
@@ -38,6 +38,7 @@ const PHI_ANTD_ICON_LOADERS = {
|
|
|
38
38
|
CalendarOutlined: () => import("@ant-design/icons-svg/es/asn/CalendarOutlined"),
|
|
39
39
|
CheckOutlined: () => import("@ant-design/icons-svg/es/asn/CheckOutlined"),
|
|
40
40
|
CloseOutlined: () => import("@ant-design/icons-svg/es/asn/CloseOutlined"),
|
|
41
|
+
CloudDownloadOutlined: () => import("@ant-design/icons-svg/es/asn/CloudDownloadOutlined"),
|
|
41
42
|
CloudUploadOutlined: () => import("@ant-design/icons-svg/es/asn/CloudUploadOutlined"),
|
|
42
43
|
ClusterOutlined: () => import("@ant-design/icons-svg/es/asn/ClusterOutlined"),
|
|
43
44
|
CodeOutlined: () => import("@ant-design/icons-svg/es/asn/CodeOutlined"),
|
|
@@ -327,6 +328,8 @@ export const PHI_ANTD_ICON_NAMES = {
|
|
|
327
328
|
"video-camera-two-tone": "VideoCameraTwoTone",
|
|
328
329
|
warning: "WarningOutlined",
|
|
329
330
|
"warning-outlined": "WarningOutlined",
|
|
331
|
+
"cloud-download": "CloudDownloadOutlined",
|
|
332
|
+
"cloud-download-outlined": "CloudDownloadOutlined",
|
|
330
333
|
"cloud-upload": "CloudUploadOutlined",
|
|
331
334
|
"cloud-upload-outlined": "CloudUploadOutlined",
|
|
332
335
|
"eye-invisible": "EyeInvisibleOutlined",
|
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
|
+
import { PHI_SHELL_STICKY_TOP_PROPERTY } from "../root/phi-shell-chrome-overlay";
|
|
3
4
|
/**
|
|
4
5
|
* How far down the viewport the Shell's Header holds right now, published on the Shell.
|
|
5
6
|
*
|
|
6
7
|
* Something that sticks to the top of the page -- a Table's header row -- has to stick under the Header
|
|
7
8
|
* rather than behind it, and where the Header ends is not a constant: each band sticks or scrolls by its
|
|
8
9
|
* own config, and a revealing `header_top` slides away while the visitor reads down and comes back when
|
|
9
|
-
* they scroll up. So the edge is measured, not configured: the lowest bottom of
|
|
10
|
-
* stuck
|
|
10
|
+
* they scroll up. So the edge is measured, not configured: the lowest visible bottom of the Header bands,
|
|
11
|
+
* stuck or in the flow, written as `--phi-shell-sticky-top` on the Shell element. Unset, a reader falls
|
|
11
12
|
* back to `0px`, which is right for a Shell without a sticky Header.
|
|
12
13
|
*
|
|
13
|
-
* Run by whatever sticks under it -- every sticky Table does
|
|
14
|
-
*
|
|
15
|
-
* Modal's or Drawer's body scrolls on
|
|
14
|
+
* Run by whatever sticks under it -- every sticky Table does, and the Region renderer for a stuck Sider
|
|
15
|
+
* (`phiCmsRegionSiderSticks`) -- so a page without one loads nothing for it. Each runner measures all the
|
|
16
|
+
* bands and they all write the same value. Not inside an Overlay: a Modal's or Drawer's body scrolls on
|
|
17
|
+
* its own, and its top edge is the line.
|
|
16
18
|
*/
|
|
17
|
-
const PHI_SHELL_STICKY_TOP_PROPERTY = "--phi-shell-sticky-top";
|
|
18
19
|
const HEADER_BANDS = '[data-phi-region-key^="header_"]:not([hidden])';
|
|
19
20
|
function measurePhiShellStickyTop(shell) {
|
|
21
|
+
/*
|
|
22
|
+
* The lowest visible bottom of the Header bands, stuck or not. Counting only the bands stuck at this
|
|
23
|
+
* moment made the edge jump: a band leaving its sticking line for its place in the flow -- the main
|
|
24
|
+
* band while the top band scrolls back in above it -- dropped out of the count at once, and whatever
|
|
25
|
+
* stuck under it leapt up by the band's height. Counted while it is in view, the edge moves with the
|
|
26
|
+
* scroll instead. A band in the flow stands above the content anyway, so nothing sticks too low for it.
|
|
27
|
+
*/
|
|
20
28
|
let bottom = 0;
|
|
21
29
|
for (const band of shell.querySelectorAll(HEADER_BANDS)) {
|
|
22
|
-
const style = window.getComputedStyle(band);
|
|
23
|
-
if (style.position !== "sticky" && style.position !== "fixed") {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
30
|
const rect = band.getBoundingClientRect();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (rect.height === 0 || rect.top > stuckAt + 1 || rect.bottom <= 0) {
|
|
31
|
+
// Empty, or scrolled or slid out of the viewport.
|
|
32
|
+
if (rect.height === 0 || rect.bottom <= 0) {
|
|
30
33
|
continue;
|
|
31
34
|
}
|
|
32
35
|
bottom = Math.max(bottom, rect.bottom);
|
|
@@ -57,10 +60,46 @@ export function usePhiShellStickyTop({ active, elementRef, }) {
|
|
|
57
60
|
}
|
|
58
61
|
};
|
|
59
62
|
publish();
|
|
63
|
+
/*
|
|
64
|
+
* A revealing band moves by a transition. Measured only where it settled, whatever sticks under it
|
|
65
|
+
* would stand still while the band slides and then jump; so while a transition runs in the Shell the
|
|
66
|
+
* edge is measured every frame, and once more where it ends.
|
|
67
|
+
*/
|
|
68
|
+
let following = 0;
|
|
69
|
+
let followFrame = 0;
|
|
70
|
+
const follow = () => {
|
|
71
|
+
publish();
|
|
72
|
+
followFrame = following > 0 ? window.requestAnimationFrame(follow) : 0;
|
|
73
|
+
};
|
|
74
|
+
// Only a Header band's own transitions move the edge; a button's hover elsewhere in the Shell does not.
|
|
75
|
+
const isBandTransition = (event) => event.target instanceof Element && event.target.closest(HEADER_BANDS) !== null;
|
|
76
|
+
// A transition whose element leaves the page never ends; the follow stops on its own regardless.
|
|
77
|
+
let followTimeout = 0;
|
|
78
|
+
const stopFollowing = () => {
|
|
79
|
+
following = 0;
|
|
80
|
+
followTimeout = 0;
|
|
81
|
+
};
|
|
82
|
+
const transitionStarted = (event) => {
|
|
83
|
+
if (!isBandTransition(event))
|
|
84
|
+
return;
|
|
85
|
+
following += 1;
|
|
86
|
+
window.clearTimeout(followTimeout);
|
|
87
|
+
followTimeout = window.setTimeout(stopFollowing, 2000);
|
|
88
|
+
if (followFrame === 0) {
|
|
89
|
+
followFrame = window.requestAnimationFrame(follow);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const transitionStopped = (event) => {
|
|
93
|
+
if (!isBandTransition(event))
|
|
94
|
+
return;
|
|
95
|
+
following = Math.max(0, following - 1);
|
|
96
|
+
schedule();
|
|
97
|
+
};
|
|
60
98
|
window.addEventListener("scroll", schedule, { passive: true });
|
|
61
99
|
window.addEventListener("resize", schedule);
|
|
62
|
-
|
|
63
|
-
shell.addEventListener("transitionend",
|
|
100
|
+
shell.addEventListener("transitionrun", transitionStarted);
|
|
101
|
+
shell.addEventListener("transitionend", transitionStopped);
|
|
102
|
+
shell.addEventListener("transitioncancel", transitionStopped);
|
|
64
103
|
const observer = new ResizeObserver(schedule);
|
|
65
104
|
for (const band of shell.querySelectorAll(HEADER_BANDS)) {
|
|
66
105
|
observer.observe(band);
|
|
@@ -69,9 +108,15 @@ export function usePhiShellStickyTop({ active, elementRef, }) {
|
|
|
69
108
|
if (frame !== 0) {
|
|
70
109
|
window.cancelAnimationFrame(frame);
|
|
71
110
|
}
|
|
111
|
+
if (followFrame !== 0) {
|
|
112
|
+
window.cancelAnimationFrame(followFrame);
|
|
113
|
+
}
|
|
114
|
+
window.clearTimeout(followTimeout);
|
|
72
115
|
window.removeEventListener("scroll", schedule);
|
|
73
116
|
window.removeEventListener("resize", schedule);
|
|
74
|
-
shell.removeEventListener("
|
|
117
|
+
shell.removeEventListener("transitionrun", transitionStarted);
|
|
118
|
+
shell.removeEventListener("transitionend", transitionStopped);
|
|
119
|
+
shell.removeEventListener("transitioncancel", transitionStopped);
|
|
75
120
|
observer.disconnect();
|
|
76
121
|
};
|
|
77
122
|
}, [active, elementRef]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useRef, useSyncExternalStore } from "react";
|
|
2
|
+
import { useCallback, useRef, useSyncExternalStore } from "react";
|
|
3
3
|
const scopedStateStoreKey = "__phiScopedStateStores__";
|
|
4
4
|
function normalizeScopedStateKey(scopeKey) {
|
|
5
5
|
return scopeKey.trim() || "default";
|
|
@@ -92,7 +92,12 @@ export function createScopedStateStore(storeId, createDefaultState) {
|
|
|
92
92
|
}
|
|
93
93
|
function useStore(scopeKey) {
|
|
94
94
|
const normalizedScopeKey = normalizeScopedStateKey(scopeKey);
|
|
95
|
-
|
|
95
|
+
/*
|
|
96
|
+
* Held per scope. An inline `subscribe` is a new function every render, and `useSyncExternalStore`
|
|
97
|
+
* unsubscribes and subscribes again for each new one.
|
|
98
|
+
*/
|
|
99
|
+
const subscribeToScope = useCallback((listener) => subscribe(normalizedScopeKey, listener), [normalizedScopeKey]);
|
|
100
|
+
return useSyncExternalStore(subscribeToScope, () => getSnapshot(normalizedScopeKey), () => getHydrationSnapshot(normalizedScopeKey));
|
|
96
101
|
}
|
|
97
102
|
function useStoreSelector(scopeKey, selector) {
|
|
98
103
|
const normalizedScopeKey = normalizeScopedStateKey(scopeKey);
|
|
@@ -124,14 +129,26 @@ export function createScopedStateStore(storeId, createDefaultState) {
|
|
|
124
129
|
selectedHydrationSnapshotRef.current = { source, selector, selected };
|
|
125
130
|
return selected;
|
|
126
131
|
};
|
|
127
|
-
|
|
132
|
+
const subscribeToScope = useCallback((listener) => subscribe(normalizedScopeKey, listener), [normalizedScopeKey]);
|
|
133
|
+
return useSyncExternalStore(subscribeToScope, getSelectedSnapshot, getSelectedHydrationSnapshot);
|
|
128
134
|
}
|
|
129
135
|
function reset(scopeKey) {
|
|
130
136
|
patch(scopeKey, () => createDefaultState(normalizeScopedStateKey(scopeKey)));
|
|
131
137
|
}
|
|
138
|
+
/*
|
|
139
|
+
* Forgets a scope's state. A component still mounted on it keeps its subscription on the entry it
|
|
140
|
+
* subscribed to, so dropping that entry left it listening to nothing: the next write went into a new
|
|
141
|
+
* entry nobody was told about. With listeners, the entry stays and starts over from the default
|
|
142
|
+
* instead, and they hear it.
|
|
143
|
+
*/
|
|
132
144
|
function deleteScope(scopeKey) {
|
|
133
145
|
const normalizedScopeKey = normalizeScopedStateKey(scopeKey);
|
|
134
146
|
const bucket = getScopedBucket();
|
|
147
|
+
const entry = bucket.get(normalizedScopeKey);
|
|
148
|
+
if (entry && entry.listeners.size > 0) {
|
|
149
|
+
replace(normalizedScopeKey, createDefaultState(normalizedScopeKey));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
135
152
|
bucket.delete(normalizedScopeKey);
|
|
136
153
|
}
|
|
137
154
|
return {
|
|
@@ -16,3 +16,16 @@ export declare function PhiSurfaceTone({ tone, children, }: {
|
|
|
16
16
|
tone: PhiSurfaceToneValue | null | undefined;
|
|
17
17
|
children: ReactNode;
|
|
18
18
|
}): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The page's own mode around something that belongs to the page's tools rather than to its content.
|
|
21
|
+
*
|
|
22
|
+
* The Builder draws its scaffolds -- tool bars, drag handles, the effects preview -- inside the Surfaces
|
|
23
|
+
* they edit, and a toned Surface would turn them with its content. This turns them back: inside a tone
|
|
24
|
+
* scope it mounts the page's mode again (its Ant Design components take it by themselves), outside one it
|
|
25
|
+
* renders the children as they are. `className` is the class an element of the caller's that reads the
|
|
26
|
+
* Theme's variables itself must carry, so they resolve in the page's mode there too; empty outside a tone.
|
|
27
|
+
*/
|
|
28
|
+
export declare function usePhiPageModeTone(): {
|
|
29
|
+
className: string | undefined;
|
|
30
|
+
wrap: (children: ReactNode) => ReactNode;
|
|
31
|
+
};
|
|
@@ -34,3 +34,24 @@ export function PhiSurfaceTone({ tone, children, }) {
|
|
|
34
34
|
}
|
|
35
35
|
return (_jsx(Suspense, { fallback: null, children: _jsx(PhiSurfaceToneScope, { mode: target, cssVarKey: cssVarKey, source: source, children: children }) }));
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The page's own mode around something that belongs to the page's tools rather than to its content.
|
|
39
|
+
*
|
|
40
|
+
* The Builder draws its scaffolds -- tool bars, drag handles, the effects preview -- inside the Surfaces
|
|
41
|
+
* they edit, and a toned Surface would turn them with its content. This turns them back: inside a tone
|
|
42
|
+
* scope it mounts the page's mode again (its Ant Design components take it by themselves), outside one it
|
|
43
|
+
* renders the children as they are. `className` is the class an element of the caller's that reads the
|
|
44
|
+
* Theme's variables itself must carry, so they resolve in the page's mode there too; empty outside a tone.
|
|
45
|
+
*/
|
|
46
|
+
export function usePhiPageModeTone() {
|
|
47
|
+
const { mode } = usePhiConfig();
|
|
48
|
+
const source = usePhiThemeToneSource();
|
|
49
|
+
const pageMode = source?.pageMode ?? mode;
|
|
50
|
+
if (pageMode === mode) {
|
|
51
|
+
return { className: undefined, wrap: (children) => children };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
className: resolvePhiSurfaceToneClassName(pageMode),
|
|
55
|
+
wrap: (children) => _jsx(PhiSurfaceTone, { tone: pageMode, children: children }),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -22,7 +22,8 @@ export declare function usePhiTableBinding({ source, initialQuery, externalQuery
|
|
|
22
22
|
resource: PhiTableProviderResourceDescriptor | null;
|
|
23
23
|
bindingError: string | null;
|
|
24
24
|
rows: readonly TableRow[];
|
|
25
|
-
total: number;
|
|
25
|
+
total: number | null;
|
|
26
|
+
hasMore: boolean;
|
|
26
27
|
summary: Readonly<Record<string, PhiTableSummaryValue>>;
|
|
27
28
|
contractError: string | null;
|
|
28
29
|
loading: boolean;
|
|
@@ -76,7 +76,14 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
76
76
|
expandedRowIdentities: initialQuery.expandedRowIdentities,
|
|
77
77
|
}));
|
|
78
78
|
const [rows, setRows] = useState([]);
|
|
79
|
-
|
|
79
|
+
/*
|
|
80
|
+
* The number of rows the whole query has, where the Provider counts them (`query.total` on its
|
|
81
|
+
* resource), and `null` where it does not. Counting is a query of its own on a large table, so a
|
|
82
|
+
* Provider answers it only where a Table shows it; the rows on this page are never put in its place.
|
|
83
|
+
*/
|
|
84
|
+
const [total, setTotal] = useState(null);
|
|
85
|
+
/** Whether a page follows this one, for a Table that pages without a count. */
|
|
86
|
+
const [hasMore, setHasMore] = useState(false);
|
|
80
87
|
const [summary, setSummary] = useState({});
|
|
81
88
|
const [queryLoading, setQueryLoading] = useState(Boolean(source));
|
|
82
89
|
const [pendingMutationTargets, setPendingMutationTargets] = useState(() => new Set());
|
|
@@ -102,6 +109,30 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
102
109
|
controller.abort();
|
|
103
110
|
mutationControllers.current.clear();
|
|
104
111
|
}, []);
|
|
112
|
+
/*
|
|
113
|
+
* A new source starts from nothing, and it does so in the render that brought it.
|
|
114
|
+
*
|
|
115
|
+
* The reset used to run in a microtask after the effects, so the query effect below had already
|
|
116
|
+
* fetched the new source with the old page and cursor -- one request thrown away on every source or
|
|
117
|
+
* `bindingParamsChange`. Adjusting state while rendering is React's way to follow a prop: the effects
|
|
118
|
+
* of this render see page 1 already. It also leaves the first render alone, so an `initialQuery` page
|
|
119
|
+
* and `initialExpandedRowIdentities` are no longer reset away on mount.
|
|
120
|
+
*/
|
|
121
|
+
const [renderedSourceKey, setRenderedSourceKey] = useState(sourceKey);
|
|
122
|
+
if (renderedSourceKey !== sourceKey) {
|
|
123
|
+
setRenderedSourceKey(sourceKey);
|
|
124
|
+
setPendingMutationTargets(new Set());
|
|
125
|
+
setRows([]);
|
|
126
|
+
setTotal(null);
|
|
127
|
+
setHasMore(false);
|
|
128
|
+
setSummary({});
|
|
129
|
+
setSelectedRowIdentities([]);
|
|
130
|
+
setExpandedRowIdentities([]);
|
|
131
|
+
setQuery((current) => ({ ...current, page: 1, cursor: null }));
|
|
132
|
+
setQueryLoading(sourceKey !== "null");
|
|
133
|
+
setError(null);
|
|
134
|
+
}
|
|
135
|
+
// What a render cannot reset: requests in flight and the bookkeeping kept beside state.
|
|
105
136
|
useEffect(() => {
|
|
106
137
|
for (const controller of mutationControllers.current)
|
|
107
138
|
controller.abort();
|
|
@@ -109,21 +140,6 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
109
140
|
latestMutationByTarget.current.clear();
|
|
110
141
|
pendingMutationCountsByTarget.current.clear();
|
|
111
142
|
rowsRef.current = [];
|
|
112
|
-
let cancelled = false;
|
|
113
|
-
queueMicrotask(() => {
|
|
114
|
-
if (cancelled)
|
|
115
|
-
return;
|
|
116
|
-
setPendingMutationTargets(new Set());
|
|
117
|
-
setRows([]);
|
|
118
|
-
setTotal(0);
|
|
119
|
-
setSummary({});
|
|
120
|
-
setSelectedRowIdentities([]);
|
|
121
|
-
setExpandedRowIdentities([]);
|
|
122
|
-
setQuery((current) => ({ ...current, page: 1, cursor: null }));
|
|
123
|
-
setQueryLoading(sourceKey !== "null");
|
|
124
|
-
setError(null);
|
|
125
|
-
});
|
|
126
|
-
return () => { cancelled = true; };
|
|
127
143
|
}, [sourceKey]);
|
|
128
144
|
/*
|
|
129
145
|
* Held by content, not identity: a caller that writes the object inline hands in a new one every
|
|
@@ -158,7 +174,8 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
158
174
|
if (data.rows.some((row) => readPhiTableRowIdentity(row, resource.rowIdentityPath) == null)) {
|
|
159
175
|
setRows([]);
|
|
160
176
|
rowsRef.current = [];
|
|
161
|
-
setTotal(
|
|
177
|
+
setTotal(null);
|
|
178
|
+
setHasMore(false);
|
|
162
179
|
setSummary({});
|
|
163
180
|
setQueryLoading(false);
|
|
164
181
|
setError(new PhiTableProviderError("missing-row-identity", `Table Provider row is missing identity field "${resource.rowIdentityPath}".`));
|
|
@@ -168,7 +185,8 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
168
185
|
if (summaryError) {
|
|
169
186
|
setRows([]);
|
|
170
187
|
rowsRef.current = [];
|
|
171
|
-
setTotal(
|
|
188
|
+
setTotal(null);
|
|
189
|
+
setHasMore(false);
|
|
172
190
|
setSummary({});
|
|
173
191
|
setQueryLoading(false);
|
|
174
192
|
setError(new PhiTableProviderError("invalid-summary", summaryError));
|
|
@@ -176,7 +194,11 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
176
194
|
}
|
|
177
195
|
rowsRef.current = data.rows;
|
|
178
196
|
setRows(data.rows);
|
|
179
|
-
|
|
197
|
+
// A resource that does not page answers every row at once, so its rows are its count.
|
|
198
|
+
const pages = resource.query.pagination === "offset" || resource.query.pagination === "cursor";
|
|
199
|
+
setTotal(data.total ?? (pages ? null : data.rows.length));
|
|
200
|
+
const pageSize = data.pageSize ?? resolvedQuery.pageSize;
|
|
201
|
+
setHasMore(data.nextCursor != null || (data.total == null && pageSize != null && data.rows.length >= pageSize));
|
|
180
202
|
setSummary(data.summary ?? {});
|
|
181
203
|
setQueryLoading(false);
|
|
182
204
|
setError(null);
|
|
@@ -188,7 +210,7 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
188
210
|
setSelectedRowIdentities((current) => current.filter((identity) => available.has(String(identity))));
|
|
189
211
|
}
|
|
190
212
|
onDataRef.current?.(data);
|
|
191
|
-
}, [preserveSelectedRowIdentities, resource]);
|
|
213
|
+
}, [preserveSelectedRowIdentities, resolvedQuery.pageSize, resource]);
|
|
192
214
|
useEffect(() => {
|
|
193
215
|
if (!source || !provider || !resource || resourceError)
|
|
194
216
|
return;
|
|
@@ -254,7 +276,8 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
254
276
|
if (!background) {
|
|
255
277
|
setRows([]);
|
|
256
278
|
rowsRef.current = [];
|
|
257
|
-
setTotal(
|
|
279
|
+
setTotal(null);
|
|
280
|
+
setHasMore(false);
|
|
258
281
|
setSummary({});
|
|
259
282
|
}
|
|
260
283
|
setQueryLoading(false);
|
|
@@ -505,6 +528,7 @@ export function usePhiTableBinding({ source, initialQuery = {}, externalQuery, f
|
|
|
505
528
|
bindingError,
|
|
506
529
|
rows,
|
|
507
530
|
total,
|
|
531
|
+
hasMore,
|
|
508
532
|
summary,
|
|
509
533
|
contractError: resourceError,
|
|
510
534
|
loading: queryLoading && !bindingError && !resourceError,
|
|
@@ -104,19 +104,27 @@ export function usePhiTreeBinding({ source, initialQuery = PHI_TREE_DEFAULT_INIT
|
|
|
104
104
|
controllers.clear();
|
|
105
105
|
};
|
|
106
106
|
}, []);
|
|
107
|
+
/*
|
|
108
|
+
* A new source, or new defaults, start the tree over -- in the render that brought them, so the query
|
|
109
|
+
* effect below asks once, with the reset query, instead of first with the old one.
|
|
110
|
+
*
|
|
111
|
+
* The search a reader typed stays. Resetting it to the initial query showed the unfiltered tree for a
|
|
112
|
+
* moment and fetched it, and the Widget's debounce put the search back 250 ms later for a third request:
|
|
113
|
+
* a new binding parameter narrows what the tree is about, not what the reader is looking for.
|
|
114
|
+
*/
|
|
115
|
+
const [renderedResetInputs, setRenderedResetInputs] = useState({ sourceKey, initialQuery, defaultExpandedNodeIdentities });
|
|
116
|
+
if (renderedResetInputs.sourceKey !== sourceKey ||
|
|
117
|
+
renderedResetInputs.initialQuery !== initialQuery ||
|
|
118
|
+
renderedResetInputs.defaultExpandedNodeIdentities !== defaultExpandedNodeIdentities) {
|
|
119
|
+
setRenderedResetInputs({ sourceKey, initialQuery, defaultExpandedNodeIdentities });
|
|
120
|
+
setNodes([]);
|
|
121
|
+
setSelectedNodeIdentities([]);
|
|
122
|
+
setCheckedNodeIdentities([]);
|
|
123
|
+
setExpandedNodeIdentities(defaultExpandedNodeIdentities);
|
|
124
|
+
setQuery((current) => (current.search ? { ...initialQuery, search: current.search } : initialQuery));
|
|
125
|
+
}
|
|
107
126
|
useEffect(() => {
|
|
108
127
|
expandedInitialSnapshot.current = false;
|
|
109
|
-
let cancelled = false;
|
|
110
|
-
queueMicrotask(() => {
|
|
111
|
-
if (cancelled)
|
|
112
|
-
return;
|
|
113
|
-
setNodes([]);
|
|
114
|
-
setSelectedNodeIdentities([]);
|
|
115
|
-
setCheckedNodeIdentities([]);
|
|
116
|
-
setExpandedNodeIdentities(defaultExpandedNodeIdentities);
|
|
117
|
-
setQuery(initialQuery);
|
|
118
|
-
});
|
|
119
|
-
return () => { cancelled = true; };
|
|
120
128
|
}, [defaultExpandedNodeIdentities, initialQuery, sourceKey]);
|
|
121
129
|
useEffect(() => {
|
|
122
130
|
if (!source || !provider || !resource)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import { type PhiBulletListEntry, type PhiResolvedBulletListStyle } from "../shared/bullet-list-vocabulary";
|
|
3
|
+
export type PhiBulletListEntriesEditorProps = {
|
|
4
|
+
entries: readonly PhiBulletListEntry[];
|
|
5
|
+
listStyle: PhiResolvedBulletListStyle;
|
|
6
|
+
/** Absent, the entries are only shown: a read-only canvas. */
|
|
7
|
+
onCommit?: (entries: PhiBulletListEntry[]) => void;
|
|
8
|
+
/** Whether a click on an entry's marker steps its state on (`PHI_BULLET_LIST_ENTRY_STATES`). */
|
|
9
|
+
states?: boolean;
|
|
10
|
+
/** Each entry's field, apart from what every field here is: borderless, its text's own type. */
|
|
11
|
+
fieldStyle?: CSSProperties;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A list written in place, entry by entry, as the Widgets that carry one edit it.
|
|
15
|
+
*
|
|
16
|
+
* Every entry is a text field standing where the entry stands, so the list is set as it will be read.
|
|
17
|
+
* What is typed stays here until the field is left, and the Builder's history records one change per
|
|
18
|
+
* entry rather than one per keystroke. What changes the list's shape is written at once, with what was
|
|
19
|
+
* typed so far: Enter opens an entry after this one, Backspace in an empty entry removes it, Tab and
|
|
20
|
+
* Shift+Tab move an entry a level down and up, and -- where the list has `states` -- a click on the
|
|
21
|
+
* marker steps the entry from included to excluded to neither. Waiting for the blur would let the entry
|
|
22
|
+
* jump back while the tree is drawn again.
|
|
23
|
+
*
|
|
24
|
+
* A list with no entries still offers one empty field, so there is something to type into.
|
|
25
|
+
*/
|
|
26
|
+
export declare function PhiBulletListEntriesEditor({ entries, listStyle, onCommit, states, fieldStyle, }: PhiBulletListEntriesEditorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
import { PhiBulletListControl } from "../../controls/phi-bullet-list-control";
|
|
5
|
+
import { PhiTextControl } from "../../controls/phi-text-control";
|
|
6
|
+
import { buildPhiBulletListTree, nextPhiBulletListEntryState, resolvePhiBulletListLevel, } from "../shared/bullet-list-vocabulary";
|
|
7
|
+
/**
|
|
8
|
+
* A list written in place, entry by entry, as the Widgets that carry one edit it.
|
|
9
|
+
*
|
|
10
|
+
* Every entry is a text field standing where the entry stands, so the list is set as it will be read.
|
|
11
|
+
* What is typed stays here until the field is left, and the Builder's history records one change per
|
|
12
|
+
* entry rather than one per keystroke. What changes the list's shape is written at once, with what was
|
|
13
|
+
* typed so far: Enter opens an entry after this one, Backspace in an empty entry removes it, Tab and
|
|
14
|
+
* Shift+Tab move an entry a level down and up, and -- where the list has `states` -- a click on the
|
|
15
|
+
* marker steps the entry from included to excluded to neither. Waiting for the blur would let the entry
|
|
16
|
+
* jump back while the tree is drawn again.
|
|
17
|
+
*
|
|
18
|
+
* A list with no entries still offers one empty field, so there is something to type into.
|
|
19
|
+
*/
|
|
20
|
+
export function PhiBulletListEntriesEditor({ entries, listStyle, onCommit, states = false, fieldStyle, }) {
|
|
21
|
+
const [draftState, setDraftState] = useState(() => ({ source: entries, value: [...entries] }));
|
|
22
|
+
const draft = draftState.source === entries ? draftState.value : [...entries];
|
|
23
|
+
const shown = draft.length > 0 || !onCommit ? draft : [{ text: "" }];
|
|
24
|
+
const listRef = useRef(null);
|
|
25
|
+
function focusEntry(index) {
|
|
26
|
+
requestAnimationFrame(() => {
|
|
27
|
+
const field = listRef.current?.querySelectorAll("textarea")[index];
|
|
28
|
+
field?.focus();
|
|
29
|
+
field?.setSelectionRange(field.value.length, field.value.length);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function commit(next) {
|
|
33
|
+
// The empty field an empty list offers is not an entry until something is typed into it.
|
|
34
|
+
if (entries.length === 0 && next.length === 1 && next[0].text === "" && !next[0].state)
|
|
35
|
+
return;
|
|
36
|
+
setDraftState({ source: entries, value: next });
|
|
37
|
+
if (JSON.stringify(next) !== JSON.stringify(entries))
|
|
38
|
+
onCommit?.(next);
|
|
39
|
+
}
|
|
40
|
+
function updateText(index, text) {
|
|
41
|
+
const next = [...shown];
|
|
42
|
+
next[index] = { ...next[index], text };
|
|
43
|
+
setDraftState({ source: entries, value: next });
|
|
44
|
+
}
|
|
45
|
+
function shiftLevel(index, delta) {
|
|
46
|
+
const entry = shown[index];
|
|
47
|
+
if (!entry)
|
|
48
|
+
return;
|
|
49
|
+
const level = resolvePhiBulletListLevel((entry.level ?? 1) + delta);
|
|
50
|
+
if (level === (entry.level ?? 1))
|
|
51
|
+
return;
|
|
52
|
+
const { level: _level, ...rest } = entry;
|
|
53
|
+
void _level;
|
|
54
|
+
commit(shown.map((item, itemIndex) => (itemIndex === index ? (level > 1 ? { ...rest, level } : rest) : item)));
|
|
55
|
+
focusEntry(index);
|
|
56
|
+
}
|
|
57
|
+
function insertAfter(index) {
|
|
58
|
+
const entry = shown[index];
|
|
59
|
+
const level = entry?.level;
|
|
60
|
+
commit([...shown.slice(0, index + 1), { text: "", ...(level ? { level } : {}) }, ...shown.slice(index + 1)]);
|
|
61
|
+
focusEntry(index + 1);
|
|
62
|
+
}
|
|
63
|
+
function remove(index) {
|
|
64
|
+
commit(shown.filter((_, itemIndex) => itemIndex !== index));
|
|
65
|
+
focusEntry(Math.max(0, index - 1));
|
|
66
|
+
}
|
|
67
|
+
function stepState(index) {
|
|
68
|
+
const entry = shown[index];
|
|
69
|
+
if (!entry)
|
|
70
|
+
return;
|
|
71
|
+
const { state: _state, ...rest } = entry;
|
|
72
|
+
void _state;
|
|
73
|
+
const state = nextPhiBulletListEntryState(entry.state);
|
|
74
|
+
commit(shown.map((item, itemIndex) => (itemIndex === index ? (state === "neutral" ? rest : { ...rest, state }) : item)));
|
|
75
|
+
}
|
|
76
|
+
return (_jsx("div", { ref: listRef, style: { width: "100%", minWidth: 0 }, children: _jsx(PhiBulletListControl, { listStyle: listStyle,
|
|
77
|
+
// Each entry is a borderless text field, whose first line stands at the field's height.
|
|
78
|
+
markerLineHeight: "var(--ant-control-height)", items: buildPhiBulletListTree(shown, (item, index) => (_jsx(PhiTextControl, { presentation: "textarea", value: item.text, readOnly: !onCommit, variant: "borderless", placeholder: `Item ${index + 1}`, autoSize: { minRows: 1, maxRows: 6 }, onChange: (value) => updateText(index, value ?? ""), onBlur: () => commit(shown), onKeyDown: (event) => {
|
|
79
|
+
if (!onCommit)
|
|
80
|
+
return;
|
|
81
|
+
if (event.key === "Tab") {
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
shiftLevel(index, event.shiftKey ? -1 : 1);
|
|
84
|
+
}
|
|
85
|
+
else if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
insertAfter(index);
|
|
88
|
+
}
|
|
89
|
+
else if (event.key === "Backspace" && item.text === "" && shown.length > 1) {
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
remove(index);
|
|
92
|
+
}
|
|
93
|
+
}, style: {
|
|
94
|
+
paddingInline: 0,
|
|
95
|
+
paddingBlock: 0,
|
|
96
|
+
borderRadius: 0,
|
|
97
|
+
borderWidth: 0,
|
|
98
|
+
backgroundColor: "transparent",
|
|
99
|
+
resize: "none",
|
|
100
|
+
color: "inherit",
|
|
101
|
+
...fieldStyle,
|
|
102
|
+
},
|
|
103
|
+
/*
|
|
104
|
+
* The text's own padding, stated: half of what the line leaves of the field's height, so the
|
|
105
|
+
* first line's middle is the marker's (`markerLineHeight` above). That is the padding the
|
|
106
|
+
* field had from Ant Design already; stated, the clear button can find the line too.
|
|
107
|
+
*/
|
|
108
|
+
inputStyle: { paddingBlock: "calc((var(--ant-control-height) - 1lh) / 2)" } })), states && onCommit ? (_entry, index) => stepState(index) : undefined) }) }));
|
|
109
|
+
}
|
|
@@ -388,7 +388,7 @@ export function PhiHtmlWidgetEditor({ blockId, html, fontFamily, fontSize, onCha
|
|
|
388
388
|
const initialHtmlRef = useRef(normalizedHtml);
|
|
389
389
|
const latestHtmlRef = useRef(normalizedHtml);
|
|
390
390
|
const resolvedFontFamily = resolvePhiWidgetFontFamily(fontFamily, fonts, token);
|
|
391
|
-
const resolvedFontSize = resolvePhiWidgetFontSize(fontSize, token, "
|
|
391
|
+
const resolvedFontSize = resolvePhiWidgetFontSize(fontSize, token, "base");
|
|
392
392
|
const editable = onChange != null;
|
|
393
393
|
useEffect(() => {
|
|
394
394
|
latestHtmlRef.current = normalizedHtml;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PhiCmsAreaKey } from "../../../../constants/cms-areas";
|
|
2
|
+
import type { PhiTreeOption } from "../../../../types/tree";
|
|
3
|
+
import type { PhiPageReferenceSelection } from "./phi-page-reference-picker";
|
|
4
|
+
type PageReferenceOptions = PhiTreeOption<PhiPageReferenceSelection>[];
|
|
5
|
+
/**
|
|
6
|
+
* The Pages of one Area a link may point at, as the tree `PhiLinkTargetControl` offers, for a surface
|
|
7
|
+
* that stands outside the Builder's own catalog: a Form's `link-target` field, the Theme's Brand.
|
|
8
|
+
*
|
|
9
|
+
* Answered by `/api/site/page-references` (`gateway/page-references-route.ts`), which merges the Area's
|
|
10
|
+
* Module Pages and Core's the way the Builder's picker does. `failed` is set when the list could not be
|
|
11
|
+
* read, so the surface can say so instead of showing an empty list that looks like a Site without Pages.
|
|
12
|
+
*/
|
|
13
|
+
export declare function usePhiPageReferenceOptions(area: PhiCmsAreaKey, logScope: string): {
|
|
14
|
+
options: PageReferenceOptions;
|
|
15
|
+
failed: boolean;
|
|
16
|
+
};
|
|
17
|
+
export {};
|