wp-typia 0.21.0 → 0.22.0

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.
@@ -1,10 +1,10 @@
1
1
  // @bun
2
2
  import {
3
3
  getPackageVersions
4
- } from "./cli-syg9qpxw.js";
4
+ } from "./cli-39er8888.js";
5
5
  import {
6
6
  seedProjectMigrations
7
- } from "./cli-jfj54qej.js";
7
+ } from "./cli-e623rs7g.js";
8
8
  import {
9
9
  ensureMigrationDirectories,
10
10
  isPlainObject,
@@ -59,7 +59,7 @@ import {
59
59
  toTitleCase,
60
60
  validateBlockSlug,
61
61
  validateNamespace
62
- } from "./cli-hx88xwr4.js";
62
+ } from "./cli-j180bk07.js";
63
63
  import {
64
64
  createManagedTempRoot
65
65
  } from "./cli-t73q5aqz.js";
@@ -5278,6 +5278,17 @@ function buildInteractivityTypesSource(variables, attributes) {
5278
5278
  { name: "maxClicks", typeExpression: "number" }
5279
5279
  ],
5280
5280
  name: `${variables.pascalCase}Context`
5281
+ },
5282
+ {
5283
+ members: [
5284
+ { name: "clicks", typeExpression: "number" },
5285
+ { name: "isAnimating", typeExpression: "boolean" },
5286
+ { name: "isVisible", typeExpression: "boolean" },
5287
+ { name: "progress", typeExpression: "number" },
5288
+ { name: "clampedClicks", typeExpression: "number" },
5289
+ { name: "isComplete", typeExpression: "boolean" }
5290
+ ],
5291
+ name: `${variables.pascalCase}State`
5281
5292
  }
5282
5293
  ],
5283
5294
  typeAliases: [
@@ -12037,6 +12048,41 @@ async function resolveTemplateSource(templateId, cwd, variables, variant) {
12037
12048
  }
12038
12049
  }
12039
12050
 
12051
+ // ../wp-typia-project-tools/src/runtime/version-floor.ts
12052
+ function parseVersionFloorParts(value) {
12053
+ return value.split(".").map((part, index) => {
12054
+ if (!/^\d+$/u.test(part)) {
12055
+ throw new Error(`parseVersionFloorParts received an invalid version floor "${value}" at segment ${index + 1}.`);
12056
+ }
12057
+ return Number.parseInt(part, 10);
12058
+ });
12059
+ }
12060
+ function compareVersionFloors(left, right) {
12061
+ const leftParts = parseVersionFloorParts(left);
12062
+ const rightParts = parseVersionFloorParts(right);
12063
+ const length = Math.max(leftParts.length, rightParts.length);
12064
+ for (let index = 0;index < length; index += 1) {
12065
+ const leftValue = leftParts[index] ?? 0;
12066
+ const rightValue = rightParts[index] ?? 0;
12067
+ if (leftValue > rightValue) {
12068
+ return 1;
12069
+ }
12070
+ if (leftValue < rightValue) {
12071
+ return -1;
12072
+ }
12073
+ }
12074
+ return 0;
12075
+ }
12076
+ function pickHigherVersionFloor(current, candidate) {
12077
+ if (!candidate) {
12078
+ return current;
12079
+ }
12080
+ if (!current) {
12081
+ return candidate;
12082
+ }
12083
+ return compareVersionFloors(current, candidate) >= 0 ? current : candidate;
12084
+ }
12085
+
12040
12086
  // ../wp-typia-project-tools/src/runtime/ai-feature-capability.ts
12041
12087
  var AI_FEATURE_DEFINITIONS = {
12042
12088
  wordpressAiClient: {
@@ -12101,39 +12147,6 @@ var DEFAULT_AI_FEATURE_REGISTRY = Object.values(AI_FEATURE_DEFINITIONS).reduce((
12101
12147
  accumulator[definition.id] = definition;
12102
12148
  return accumulator;
12103
12149
  }, {});
12104
- function parseVersionFloorParts(value) {
12105
- return value.split(".").map((part, index) => {
12106
- if (!/^\d+$/.test(part)) {
12107
- throw new Error(`parseVersionFloorParts received an invalid version floor "${value}" at segment ${index + 1}.`);
12108
- }
12109
- return Number.parseInt(part, 10);
12110
- });
12111
- }
12112
- function compareVersionFloors(left, right) {
12113
- const leftParts = parseVersionFloorParts(left);
12114
- const rightParts = parseVersionFloorParts(right);
12115
- const length = Math.max(leftParts.length, rightParts.length);
12116
- for (let index = 0;index < length; index += 1) {
12117
- const leftValue = leftParts[index] ?? 0;
12118
- const rightValue = rightParts[index] ?? 0;
12119
- if (leftValue > rightValue) {
12120
- return 1;
12121
- }
12122
- if (leftValue < rightValue) {
12123
- return -1;
12124
- }
12125
- }
12126
- return 0;
12127
- }
12128
- function pickHigherVersionFloor(current, candidate) {
12129
- if (!candidate) {
12130
- return current;
12131
- }
12132
- if (!current) {
12133
- return candidate;
12134
- }
12135
- return compareVersionFloors(current, candidate) >= 0 ? current : candidate;
12136
- }
12137
12150
  function normalizeSelections(selections) {
12138
12151
  const normalized = new Map;
12139
12152
  for (const selection of selections) {
@@ -12198,35 +12211,8 @@ var REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY = [
12198
12211
  mode: "required"
12199
12212
  }
12200
12213
  ];
12201
- function parseVersionFloorParts2(value) {
12202
- return value.split(".").map((part, index) => {
12203
- if (!/^\d+$/u.test(part)) {
12204
- throw new Error(`parseVersionFloorParts received an invalid version floor "${value}" at segment ${index + 1}.`);
12205
- }
12206
- return Number.parseInt(part, 10);
12207
- });
12208
- }
12209
- function compareVersionFloors2(left, right) {
12210
- const leftParts = parseVersionFloorParts2(left);
12211
- const rightParts = parseVersionFloorParts2(right);
12212
- const length = Math.max(leftParts.length, rightParts.length);
12213
- for (let index = 0;index < length; index += 1) {
12214
- const leftValue = leftParts[index] ?? 0;
12215
- const rightValue = rightParts[index] ?? 0;
12216
- if (leftValue > rightValue) {
12217
- return 1;
12218
- }
12219
- if (leftValue < rightValue) {
12220
- return -1;
12221
- }
12222
- }
12223
- return 0;
12224
- }
12225
- function pickHigherVersionFloor2(current, candidate) {
12226
- if (!candidate) {
12227
- return current;
12228
- }
12229
- return compareVersionFloors2(current, candidate) >= 0 ? current : candidate;
12214
+ function pickHigherScaffoldVersionFloor(current, candidate) {
12215
+ return pickHigherVersionFloor(current, candidate) ?? current;
12230
12216
  }
12231
12217
  function pickHigherHeaderVersionFloor(policyValue, currentValue) {
12232
12218
  const normalizedCurrentValue = currentValue.trim();
@@ -12234,7 +12220,7 @@ function pickHigherHeaderVersionFloor(policyValue, currentValue) {
12234
12220
  return policyValue;
12235
12221
  }
12236
12222
  try {
12237
- return pickHigherVersionFloor2(policyValue, normalizedCurrentValue);
12223
+ return pickHigherScaffoldVersionFloor(policyValue, normalizedCurrentValue);
12238
12224
  } catch {
12239
12225
  return policyValue;
12240
12226
  }
@@ -12255,9 +12241,9 @@ function resolveScaffoldCompatibilityPolicy(selections, {
12255
12241
  baseline = DEFAULT_SCAFFOLD_COMPATIBILITY
12256
12242
  } = {}) {
12257
12243
  const capabilityPlan = resolveAiFeatureCapabilityPlan(selections);
12258
- const requiresAtLeast = pickHigherVersionFloor2(baseline.requiresAtLeast, capabilityPlan.hardMinimums.wordpress);
12259
- const requiresPhp = pickHigherVersionFloor2(baseline.requiresPhp, capabilityPlan.hardMinimums.php);
12260
- const testedUpTo = pickHigherVersionFloor2(baseline.testedUpTo, requiresAtLeast);
12244
+ const requiresAtLeast = pickHigherScaffoldVersionFloor(baseline.requiresAtLeast, capabilityPlan.hardMinimums.wordpress);
12245
+ const requiresPhp = pickHigherScaffoldVersionFloor(baseline.requiresPhp, capabilityPlan.hardMinimums.php);
12246
+ const testedUpTo = pickHigherScaffoldVersionFloor(baseline.testedUpTo, requiresAtLeast);
12261
12247
  return {
12262
12248
  capabilityPlan,
12263
12249
  pluginHeader: {
@@ -14060,6 +14046,7 @@ import { useBlockProps, InspectorControls, RichText, BlockControls, AlignmentToo
14060
14046
  import { PanelBody, RangeControl, Button, Notice } from '@wordpress/components';
14061
14047
  import { useState } from '@wordpress/element';
14062
14048
  import currentManifest from './manifest-document';
14049
+ import { {{slugCamelCase}}Store } from './interactivity-store';
14063
14050
  import {
14064
14051
  InspectorFromManifest,
14065
14052
  useEditorFields,
@@ -14140,17 +14127,22 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14140
14127
 
14141
14128
  const blockProps = useBlockProps({
14142
14129
  className: \`{{cssClassName}} {{cssClassName}}--\${interactiveMode}\`,
14143
- 'data-wp-interactive': '{{slugKebabCase}}',
14144
- 'data-wp-context': JSON.stringify({
14145
- clicks: clickCount,
14146
- isAnimating,
14147
- isVisible,
14148
- animation,
14149
- maxClicks,
14150
- })
14130
+ 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,
14131
+ 'data-wp-context': JSON.stringify(
14132
+ {{slugCamelCase}}Store.createContext({
14133
+ clicks: clickCount,
14134
+ isAnimating,
14135
+ isVisible,
14136
+ animation,
14137
+ maxClicks,
14138
+ })
14139
+ )
14151
14140
  });
14152
14141
  const previewContentStyle = { textAlign: alignmentValue };
14153
14142
  const progressBarStyle = { width: \`\${(clickCount / maxClicks) * 100}%\` };
14143
+ const clicksDirective = {{slugCamelCase}}Store.directive.state('clicks');
14144
+ const isAnimatingDirective = {{slugCamelCase}}Store.directive.state('isAnimating');
14145
+ const progressDirective = {{slugCamelCase}}Store.directive.state('progress') + " + '%'";
14154
14146
 
14155
14147
  const resetCounter = () => {
14156
14148
  updateField('clickCount', 0);
@@ -14247,9 +14239,9 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14247
14239
  <div
14248
14240
  className={\`{{cssClassName}}__content \${isAnimating ? 'is-animating' : ''}\`}
14249
14241
  style={previewContentStyle}
14250
- data-wp-on--click={isPreviewing ? 'actions.handleClick' : undefined}
14251
- data-wp-on--mouseenter={isPreviewing && interactiveMode === 'hover' ? 'actions.handleMouseEnter' : undefined}
14252
- data-wp-on--mouseleave={isPreviewing && interactiveMode === 'hover' ? 'actions.handleMouseLeave' : undefined}
14242
+ data-wp-on--click={isPreviewing ? {{slugCamelCase}}Store.directive.action('handleClick') : undefined}
14243
+ data-wp-on--mouseenter={isPreviewing && interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseEnter') : undefined}
14244
+ data-wp-on--mouseleave={isPreviewing && interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseLeave') : undefined}
14253
14245
  >
14254
14246
  <RichText
14255
14247
  tagName="p"
@@ -14278,7 +14270,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14278
14270
  </span>
14279
14271
  <span
14280
14272
  className="{{cssClassName}}__counter-value"
14281
- data-wp-text="state.clicks"
14273
+ data-wp-text={clicksDirective}
14282
14274
  >
14283
14275
  {clickCount}
14284
14276
  </span>
@@ -14290,7 +14282,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14290
14282
  <div
14291
14283
  className="{{cssClassName}}__progress-bar"
14292
14284
  style={progressBarStyle}
14293
- data-wp-style--width="state.progress + '%'"
14285
+ data-wp-style--width={progressDirective}
14294
14286
  />
14295
14287
  </div>
14296
14288
  )}
@@ -14298,7 +14290,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14298
14290
  {animation !== 'none' && (
14299
14291
  <div
14300
14292
  className={\`{{cssClassName}}__animation \${isAnimating ? 'is-active' : ''}\`}
14301
- data-wp-class--is-active="state.isAnimating"
14293
+ data-wp-class--is-active={isAnimatingDirective}
14302
14294
  >
14303
14295
  {animation}
14304
14296
  </div>
@@ -14311,6 +14303,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
14311
14303
  `;
14312
14304
  var INTERACTIVITY_SAVE_TEMPLATE = `import { useBlockProps, RichText } from '@wordpress/block-editor';
14313
14305
  import { __ } from '@wordpress/i18n';
14306
+ import { {{slugCamelCase}}Store } from './interactivity-store';
14314
14307
  import type { {{pascalCase}}Attributes } from './types';
14315
14308
 
14316
14309
  export default function Save({ attributes }: { attributes: {{pascalCase}}Attributes }) {
@@ -14322,27 +14315,41 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14322
14315
  const maxClicks = attributes.maxClicks ?? 0;
14323
14316
  const showCounter = attributes.showCounter ?? true;
14324
14317
  const contentStyle = { textAlign: attributes.alignment };
14318
+ const clickActionDirective = {{slugCamelCase}}Store.directive.action('handleClick');
14319
+ const visibilityHiddenDirective = {{slugCamelCase}}Store.directive.negate(
14320
+ {{slugCamelCase}}Store.directive.state('isVisible')
14321
+ );
14322
+ const clicksDirective = {{slugCamelCase}}Store.directive.state('clicks');
14323
+ const clampedClicksDirective = {{slugCamelCase}}Store.directive.state('clampedClicks');
14324
+ const isAnimatingDirective = {{slugCamelCase}}Store.directive.state('isAnimating');
14325
+ const completionHiddenDirective = {{slugCamelCase}}Store.directive.negate(
14326
+ {{slugCamelCase}}Store.directive.state('isComplete')
14327
+ );
14328
+ const resetActionDirective = {{slugCamelCase}}Store.directive.action('reset');
14325
14329
  const blockProps = useBlockProps.save({
14326
14330
  className: \`{{cssClassName}} {{cssClassName}}--\${interactiveMode}\`,
14327
- 'data-wp-interactive': '{{slugKebabCase}}',
14328
- 'data-wp-context': JSON.stringify({
14329
- clicks: clickCount,
14330
- isAnimating,
14331
- isVisible,
14332
- animation,
14333
- maxClicks,
14334
- })
14331
+ 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,
14332
+ 'data-wp-context': JSON.stringify(
14333
+ {{slugCamelCase}}Store.createContext({
14334
+ clicks: clickCount,
14335
+ isAnimating,
14336
+ isVisible,
14337
+ animation,
14338
+ maxClicks,
14339
+ })
14340
+ )
14335
14341
  });
14342
+ const progressDirective = {{slugCamelCase}}Store.directive.state('progress') + " + '%'";
14336
14343
 
14337
14344
  return (
14338
14345
  <div {...blockProps}>
14339
14346
  <div
14340
14347
  className={\`{{cssClassName}}__content \${isAnimating ? 'is-animating' : ''}\`}
14341
14348
  style={contentStyle}
14342
- data-wp-on--click="actions.handleClick"
14343
- data-wp-on--mouseenter={interactiveMode === 'hover' ? 'actions.handleMouseEnter' : undefined}
14344
- data-wp-on--mouseleave={interactiveMode === 'hover' ? 'actions.handleMouseLeave' : undefined}
14345
- data-wp-bind--hidden="!state.isVisible"
14349
+ data-wp-on--click={clickActionDirective}
14350
+ data-wp-on--mouseenter={interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseEnter') : undefined}
14351
+ data-wp-on--mouseleave={interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseLeave') : undefined}
14352
+ data-wp-bind--hidden={visibilityHiddenDirective}
14346
14353
  >
14347
14354
  <RichText.Content
14348
14355
  tagName="p"
@@ -14362,7 +14369,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14362
14369
  </span>
14363
14370
  <span
14364
14371
  className="{{cssClassName}}__counter-value"
14365
- data-wp-text="state.clicks"
14372
+ data-wp-text={clicksDirective}
14366
14373
  >
14367
14374
  {clickCount}
14368
14375
  </span>
@@ -14378,8 +14385,8 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14378
14385
  aria-valuemin={0}
14379
14386
  aria-valuemax={maxClicks}
14380
14387
  aria-valuenow={Math.min(clickCount, maxClicks)}
14381
- data-wp-bind--aria-valuenow="state.clampedClicks"
14382
- data-wp-style--width="state.progress + '%'"
14388
+ data-wp-bind--aria-valuenow={clampedClicksDirective}
14389
+ data-wp-style--width={progressDirective}
14383
14390
  />
14384
14391
  </div>
14385
14392
  )}
@@ -14387,7 +14394,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14387
14394
  <div
14388
14395
  className={\`{{cssClassName}}__animation \${animation}\`}
14389
14396
  aria-hidden="true"
14390
- data-wp-class--is-active="state.isAnimating"
14397
+ data-wp-class--is-active={isAnimatingDirective}
14391
14398
  />
14392
14399
 
14393
14400
  {maxClicks > 0 && (
@@ -14396,7 +14403,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14396
14403
  role="status"
14397
14404
  aria-live="polite"
14398
14405
  aria-atomic="true"
14399
- data-wp-bind--hidden="!state.isComplete"
14406
+ data-wp-bind--hidden={completionHiddenDirective}
14400
14407
  >
14401
14408
  { __( '\uD83C\uDF89 Complete!', '{{textDomain}}' ) }
14402
14409
  </div>
@@ -14404,7 +14411,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
14404
14411
 
14405
14412
  <button
14406
14413
  className="{{cssClassName}}__reset"
14407
- data-wp-on--click="actions.reset"
14414
+ data-wp-on--click={resetActionDirective}
14408
14415
  aria-label={ __( 'Reset counter', '{{textDomain}}' ) }
14409
14416
  >
14410
14417
  <span aria-hidden="true">\u21BB</span>
@@ -14454,20 +14461,214 @@ const registration = buildScaffoldBlockRegistration(
14454
14461
 
14455
14462
  registerScaffoldBlockType(registration.name, registration.settings);
14456
14463
  `;
14464
+ var INTERACTIVITY_STORE_TEMPLATE = `import type {
14465
+ {{pascalCase}}Context,
14466
+ {{pascalCase}}State,
14467
+ } from './types';
14468
+
14469
+ type InteractivityActionShape = object;
14470
+ type InteractivityCallbackShape = object;
14471
+ type InteractivityContextShape = object;
14472
+ type InteractivityStateShape = object;
14473
+ type InteractivityCallable = Function;
14474
+ type InteractivityKey<T extends object> = Extract<keyof T, string>;
14475
+ type InteractivityMethodKey<T extends object> = {
14476
+ [Key in InteractivityKey<T>]: T[Key] extends InteractivityCallable ? Key : never;
14477
+ }[InteractivityKey<T>];
14478
+
14479
+ type InteractivityDirectivePath<
14480
+ Root extends string,
14481
+ Key extends string,
14482
+ > = \`\${Root}.\${Key}\`;
14483
+
14484
+ type NegatedInteractivityDirectivePath<Path extends string> = \`!\${Path}\`;
14485
+
14486
+ export interface TypedInteractivityDirectiveHelpers<
14487
+ State extends InteractivityStateShape,
14488
+ Context extends InteractivityContextShape,
14489
+ Actions extends InteractivityActionShape,
14490
+ Callbacks extends InteractivityCallbackShape,
14491
+ Namespace extends string,
14492
+ > {
14493
+ readonly interactive: Namespace;
14494
+ action<Key extends InteractivityMethodKey<Actions>>(
14495
+ key: Key,
14496
+ ): InteractivityDirectivePath<'actions', Key>;
14497
+ callback<Key extends InteractivityMethodKey<Callbacks>>(
14498
+ key: Key,
14499
+ ): InteractivityDirectivePath<'callbacks', Key>;
14500
+ state<Key extends InteractivityKey<State>>(
14501
+ key: Key,
14502
+ ): InteractivityDirectivePath<'state', Key>;
14503
+ context<Key extends InteractivityKey<Context>>(
14504
+ key: Key,
14505
+ ): InteractivityDirectivePath<'context', Key>;
14506
+ negate<Path extends string>(
14507
+ path: Path,
14508
+ ): NegatedInteractivityDirectivePath<Path>;
14509
+ }
14510
+
14511
+ export interface TypedInteractivityStore<
14512
+ Namespace extends string,
14513
+ State extends InteractivityStateShape,
14514
+ Context extends InteractivityContextShape,
14515
+ Actions extends InteractivityActionShape,
14516
+ Callbacks extends InteractivityCallbackShape,
14517
+ > {
14518
+ readonly namespace: Namespace;
14519
+ readonly state: State;
14520
+ readonly context: Context;
14521
+ readonly actions: Actions;
14522
+ readonly callbacks: Callbacks;
14523
+ readonly directive: TypedInteractivityDirectiveHelpers<
14524
+ State,
14525
+ Context,
14526
+ Actions,
14527
+ Callbacks,
14528
+ Namespace
14529
+ >;
14530
+ createContext(value: Context): Context;
14531
+ }
14532
+
14533
+ export function defineInteractivityStore<
14534
+ Namespace extends string,
14535
+ State extends InteractivityStateShape,
14536
+ Context extends InteractivityContextShape,
14537
+ Actions extends InteractivityActionShape,
14538
+ Callbacks extends InteractivityCallbackShape,
14539
+ >(config: {
14540
+ readonly namespace: Namespace;
14541
+ readonly state: State;
14542
+ readonly context: Context;
14543
+ readonly actions: Actions;
14544
+ readonly callbacks: Callbacks;
14545
+ }): TypedInteractivityStore<Namespace, State, Context, Actions, Callbacks> {
14546
+ return {
14547
+ namespace: config.namespace,
14548
+ state: config.state,
14549
+ context: config.context,
14550
+ actions: config.actions,
14551
+ callbacks: config.callbacks,
14552
+ directive: {
14553
+ interactive: config.namespace,
14554
+ action<Key extends InteractivityMethodKey<Actions>>(key: Key) {
14555
+ return \`actions.\${key}\` as InteractivityDirectivePath<'actions', Key>;
14556
+ },
14557
+ callback<Key extends InteractivityMethodKey<Callbacks>>(key: Key) {
14558
+ return \`callbacks.\${key}\` as InteractivityDirectivePath<'callbacks', Key>;
14559
+ },
14560
+ state<Key extends InteractivityKey<State>>(key: Key) {
14561
+ return \`state.\${key}\` as InteractivityDirectivePath<'state', Key>;
14562
+ },
14563
+ context<Key extends InteractivityKey<Context>>(key: Key) {
14564
+ return \`context.\${key}\` as InteractivityDirectivePath<'context', Key>;
14565
+ },
14566
+ negate<Path extends string>(path: Path) {
14567
+ return \`!\${path}\` as NegatedInteractivityDirectivePath<Path>;
14568
+ },
14569
+ },
14570
+ createContext(value) {
14571
+ return value;
14572
+ },
14573
+ };
14574
+ }
14575
+
14576
+ type InteractivityActionHandler = Function;
14577
+
14578
+ export interface {{pascalCase}}StoreActions {
14579
+ handleClick: InteractivityActionHandler;
14580
+ handleMouseEnter: InteractivityActionHandler;
14581
+ handleMouseLeave: InteractivityActionHandler;
14582
+ reset: InteractivityActionHandler;
14583
+ }
14584
+
14585
+ export interface {{pascalCase}}StoreCallbacks {}
14586
+
14587
+ export const {{slugCamelCase}}Store = defineInteractivityStore({
14588
+ namespace: '{{slugKebabCase}}',
14589
+ state: {} as {{pascalCase}}State,
14590
+ context: {} as {{pascalCase}}Context,
14591
+ actions: {} as {{pascalCase}}StoreActions,
14592
+ callbacks: {} as {{pascalCase}}StoreCallbacks,
14593
+ });
14594
+ `;
14457
14595
  var INTERACTIVITY_SCRIPT_TEMPLATE = `/**
14458
14596
  * WordPress Interactivity API implementation for {{title}} block
14459
14597
  */
14460
14598
  import { store, getContext, getElement, withSyncEvent } from '@wordpress/interactivity';
14461
- import type { {{pascalCase}}Context } from './types';
14599
+ import {
14600
+ {{slugCamelCase}}Store,
14601
+ type {{pascalCase}}StoreActions,
14602
+ } from './interactivity-store';
14603
+ import type { {{pascalCase}}Context, {{pascalCase}}State } from './types';
14462
14604
 
14463
14605
  function getBlockContext() {
14464
14606
  return getContext<{{pascalCase}}Context>();
14465
14607
  }
14466
14608
 
14467
- // Store configuration
14468
- store('{{slugKebabCase}}', {
14469
- // State - reactive data that updates the UI
14470
- state: {
14609
+ const actions: {{pascalCase}}StoreActions = {
14610
+ // Handle block click
14611
+ handleClick: () => {
14612
+ const context = getBlockContext();
14613
+ const { ref } = getElement();
14614
+
14615
+ if (!ref) {
14616
+ return;
14617
+ }
14618
+
14619
+ if (context.maxClicks > 0 && context.clicks >= context.maxClicks) {
14620
+ return;
14621
+ }
14622
+
14623
+ const previousClicks = context.clicks;
14624
+
14625
+ // Increment click counter
14626
+ context.clicks += 1;
14627
+
14628
+ // Trigger animation
14629
+ if (context.animation !== 'none') {
14630
+ context.isAnimating = true;
14631
+ setTimeout(() => {
14632
+ context.isAnimating = false;
14633
+ }, 1000);
14634
+ }
14635
+
14636
+ // Emit custom event
14637
+ ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:click', {
14638
+ detail: { clicks: context.clicks }
14639
+ }));
14640
+
14641
+ // Check if max clicks reached
14642
+ if (context.maxClicks > 0 && previousClicks < context.maxClicks && context.clicks === context.maxClicks) {
14643
+ ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:complete', {
14644
+ detail: { totalClicks: context.clicks }
14645
+ }));
14646
+ }
14647
+ },
14648
+
14649
+ // Handle hover events
14650
+ handleMouseEnter: () => {
14651
+ const context = getBlockContext();
14652
+ if (context.animation === 'none') return;
14653
+ context.isAnimating = true;
14654
+ },
14655
+
14656
+ handleMouseLeave: () => {
14657
+ const context = getBlockContext();
14658
+ if (context.animation === 'none') return;
14659
+ context.isAnimating = false;
14660
+ },
14661
+
14662
+ // Reset counter
14663
+ reset: withSyncEvent((event: Event) => {
14664
+ event.stopPropagation();
14665
+ const context = getBlockContext();
14666
+ context.clicks = 0;
14667
+ context.isAnimating = false;
14668
+ })
14669
+ };
14670
+
14671
+ const state = {
14471
14672
  get clicks() {
14472
14673
  return getBlockContext().clicks;
14473
14674
  },
@@ -14495,70 +14696,14 @@ store('{{slugKebabCase}}', {
14495
14696
  const context = getBlockContext();
14496
14697
  return context.clicks >= context.maxClicks && context.maxClicks > 0;
14497
14698
  }
14498
- },
14499
-
14500
- // Actions - user interactions
14501
- actions: {
14502
- // Handle block click
14503
- handleClick: () => {
14504
- const context = getBlockContext();
14505
- const { ref } = getElement();
14506
-
14507
- if (!ref) {
14508
- return;
14509
- }
14510
-
14511
- if (context.maxClicks > 0 && context.clicks >= context.maxClicks) {
14512
- return;
14513
- }
14514
-
14515
- const previousClicks = context.clicks;
14516
-
14517
- // Increment click counter
14518
- context.clicks += 1;
14699
+ } satisfies {{pascalCase}}State;
14519
14700
 
14520
- // Trigger animation
14521
- if (context.animation !== 'none') {
14522
- context.isAnimating = true;
14523
- setTimeout(() => {
14524
- context.isAnimating = false;
14525
- }, 1000);
14526
- }
14527
-
14528
- // Emit custom event
14529
- ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:click', {
14530
- detail: { clicks: context.clicks }
14531
- }));
14532
-
14533
- // Check if max clicks reached
14534
- if (context.maxClicks > 0 && previousClicks < context.maxClicks && context.clicks === context.maxClicks) {
14535
- ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:complete', {
14536
- detail: { totalClicks: context.clicks }
14537
- }));
14538
- }
14539
- },
14540
-
14541
- // Handle hover events
14542
- handleMouseEnter: () => {
14543
- const context = getBlockContext();
14544
- if (context.animation === 'none') return;
14545
- context.isAnimating = true;
14546
- },
14547
-
14548
- handleMouseLeave: () => {
14549
- const context = getBlockContext();
14550
- if (context.animation === 'none') return;
14551
- context.isAnimating = false;
14552
- },
14553
-
14554
- // Reset counter
14555
- reset: withSyncEvent((event: Event) => {
14556
- event.stopPropagation();
14557
- const context = getBlockContext();
14558
- context.clicks = 0;
14559
- context.isAnimating = false;
14560
- })
14561
- }
14701
+ // Store configuration
14702
+ store({{slugCamelCase}}Store.namespace, {
14703
+ // State - reactive data that updates the UI
14704
+ state,
14705
+ actions,
14706
+ callbacks: {{slugCamelCase}}Store.callbacks,
14562
14707
  });
14563
14708
  `;
14564
14709
  var INTERACTIVITY_VALIDATORS_TEMPLATE = `import typia from 'typia';
@@ -16371,6 +16516,10 @@ function buildInteractivityCodeArtifacts(variables) {
16371
16516
  relativePath: "src/interactivity.ts",
16372
16517
  template: INTERACTIVITY_SCRIPT_TEMPLATE
16373
16518
  },
16519
+ {
16520
+ relativePath: "src/interactivity-store.ts",
16521
+ template: INTERACTIVITY_STORE_TEMPLATE
16522
+ },
16374
16523
  {
16375
16524
  relativePath: "src/validators.ts",
16376
16525
  template: INTERACTIVITY_VALIDATORS_TEMPLATE
@@ -17133,6 +17282,8 @@ async function resolveOptionalInteractiveExternalLayerId({
17133
17282
  callerCwd,
17134
17283
  externalLayerId,
17135
17284
  externalLayerSource,
17285
+ listExternalTemplateLayers = listSelectableExternalTemplateLayers,
17286
+ resolveExternalTemplateSeed = resolveTemplateSeed,
17136
17287
  selectExternalLayerId
17137
17288
  }) {
17138
17289
  if (!externalLayerSource || externalLayerId || !selectExternalLayerId) {
@@ -17141,9 +17292,9 @@ async function resolveOptionalInteractiveExternalLayerId({
17141
17292
  externalLayerSource
17142
17293
  };
17143
17294
  }
17144
- const layerSeed = await resolveTemplateSeed(parseTemplateLocator(externalLayerSource), callerCwd);
17295
+ const layerSeed = await resolveExternalTemplateSeed(parseTemplateLocator(externalLayerSource), callerCwd);
17145
17296
  try {
17146
- const selectableLayers = await listSelectableExternalTemplateLayers(layerSeed.rootDir);
17297
+ const selectableLayers = await listExternalTemplateLayers(layerSeed.rootDir);
17147
17298
  if (selectableLayers.length <= 1) {
17148
17299
  await layerSeed.cleanup?.();
17149
17300
  return {
@@ -17159,7 +17310,6 @@ async function resolveOptionalInteractiveExternalLayerId({
17159
17310
  externalLayerSource: layerSeed.rootDir
17160
17311
  };
17161
17312
  }
17162
- await layerSeed.cleanup?.();
17163
17313
  throw new Error(`Unknown external layer "${selectedLayerId}". Expected one of: ${selectableLayers.map((layer) => layer.id).join(", ")}`);
17164
17314
  } catch (error) {
17165
17315
  await layerSeed.cleanup?.();
@@ -17169,4 +17319,4 @@ async function resolveOptionalInteractiveExternalLayerId({
17169
17319
 
17170
17320
  export { syncPersistenceRestArtifacts, copyInterpolatedDirectory, listInterpolatedDirectoryOutputs, getPrimaryDevelopmentScript, getOptionalOnboardingSteps, getOptionalOnboardingNote, getOptionalOnboardingShortNote, formatNonEmptyTargetDirectoryError, require_semver2 as require_semver, parseTemplateLocator, resolveExternalTemplateLayers, resolveTemplateSeed, normalizeOptionalCliString, resolveLocalCliPathOption, assertExternalLayerCompositionOptions, assertBuiltInTemplateVariantAllowed, parseAlternateRenderTargets, parseCompoundInnerBlocksPreset, OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY, REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY, resolveScaffoldCompatibilityPolicy, renderScaffoldCompatibilityConfig, updatePluginHeaderCompatibility, getDefaultAnswers, resolveTemplateId, resolvePackageManagerId, collectScaffoldAnswers, DATA_STORAGE_MODES, PERSISTENCE_POLICIES, isDataStorageMode, isPersistencePolicy, scaffoldProject, resolveOptionalInteractiveExternalLayerId };
17171
17321
 
17172
- //# debugId=EFE0A10933AD252664756E2164756E21
17322
+ //# debugId=C53957BD2FAAAD8464756E2164756E21