1- import React from 'react' ;
1+ import React , { useState , useRef } from 'react' ;
22import type { ComponentMeta } from '@storybook/react' ;
33import {
44 DeleteMinor ,
77 ExternalMinor ,
88 ViewMinor ,
99 MobileVerticalDotsMajor ,
10+ ChevronDownMinor ,
1011} from '@shopify/polaris-icons' ;
1112import {
1213 Badge ,
@@ -15,6 +16,13 @@ import {
1516 Page ,
1617 PageActions ,
1718 LegacyStack ,
19+ Popover ,
20+ ActionList ,
21+ ButtonGroup ,
22+ TextField ,
23+ FormLayout ,
24+ ContextualSaveBar ,
25+ Frame ,
1826} from '@shopify/polaris' ;
1927
2028export default {
@@ -346,3 +354,177 @@ export function WithContentAfterTitle() {
346354 </ Page >
347355 ) ;
348356}
357+
358+ export function WithSplitSaveAction ( ) {
359+ const initialState = {
360+ title : 'Jar With Lock-Lid' ,
361+ description : '' ,
362+ isDraft : false ,
363+ } ;
364+
365+ const [ active , setActive ] = React . useState ( false ) ;
366+ const [ title , setTitle ] = useState ( 'Jar With Lock-Lid' ) ;
367+ const [ description , setDescription ] = useState ( '' ) ;
368+ const [ isDirty , setIsDirty ] = useState ( false ) ;
369+ const [ isDraft , setIsDraft ] = useState ( false ) ;
370+
371+ const savedEditHistory = useRef <
372+ {
373+ title : string ;
374+ description : string ;
375+ isDraft : boolean ;
376+ } [ ]
377+ > ( [ ] ) ;
378+
379+ const handleChange = ( name : string ) => ( value : string ) => {
380+ switch ( name ) {
381+ case 'title' :
382+ handleDirtyState ( name , value , title ) ;
383+ setTitle ( value ) ;
384+ break ;
385+ case 'description' :
386+ handleDirtyState ( name , value , description ) ;
387+ setDescription ( value ) ;
388+ break ;
389+ default :
390+ null ;
391+ }
392+ } ;
393+
394+ const handleDirtyState = (
395+ name : string ,
396+ newValue : string ,
397+ currentValue : string ,
398+ ) => {
399+ if (
400+ ( newValue !== initialState [ name ] && ! isDirty ) ||
401+ newValue !== currentValue
402+ ) {
403+ setIsDirty ( true ) ;
404+ } else {
405+ setIsDirty ( false ) ;
406+ }
407+ } ;
408+
409+ const handleDiscard = ( ) => {
410+ const previousState : {
411+ title : string ;
412+ description : string ;
413+ isDraft : boolean ;
414+ } = savedEditHistory . current . pop ( ) ?? initialState ;
415+
416+ setTitle ( previousState . title ) ;
417+ setDescription ( previousState . description ) ;
418+ setIsDraft ( previousState . isDraft ) ;
419+ setIsDirty ( false ) ;
420+ } ;
421+
422+ const splitButton = (
423+ < ButtonGroup segmented >
424+ < Button
425+ size = "large"
426+ onClick = { ( ) => {
427+ savedEditHistory . current . push ( { title, description, isDraft : false } ) ;
428+ setIsDirty ( false ) ;
429+ setIsDraft ( false ) ;
430+ } }
431+ >
432+ Save
433+ </ Button >
434+
435+ < Popover
436+ active = { active }
437+ preferredAlignment = "right"
438+ activator = {
439+ < Button
440+ size = "large"
441+ onClick = { ( ) => setActive ( true ) }
442+ icon = { ChevronDownMinor }
443+ accessibilityLabel = "Other save actions"
444+ />
445+ }
446+ autofocusTarget = "first-node"
447+ onClose = { ( ) => setActive ( false ) }
448+ zIndexOverride = { 514 }
449+ >
450+ < ActionList
451+ actionRole = "menuitem"
452+ items = { [
453+ {
454+ content : 'Save as draft' ,
455+ onAction : ( ) => {
456+ setIsDraft ( true ) ;
457+ savedEditHistory . current . push ( {
458+ title,
459+ description,
460+ isDraft : true ,
461+ } ) ;
462+ } ,
463+ } ,
464+ ] }
465+ onActionAnyItem = { ( ) => setIsDirty ( false ) }
466+ />
467+ </ Popover >
468+ </ ButtonGroup >
469+ ) ;
470+
471+ const saveBar = isDirty ? (
472+ < ContextualSaveBar
473+ message = "Unsaved changes"
474+ saveAction = { splitButton }
475+ discardAction = { {
476+ content : 'Discard' ,
477+ onAction : handleDiscard ,
478+ } }
479+ />
480+ ) : null ;
481+
482+ console . log ( savedEditHistory ) ;
483+
484+ return (
485+ < Frame
486+ logo = { {
487+ width : 124 ,
488+ contextualSaveBarSource :
489+ 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999' ,
490+ } }
491+ >
492+ { saveBar }
493+ < Page
494+ backAction = { { content : 'Products' , url : '#' } }
495+ title = "Jar With Lock-Lid"
496+ titleMetadata = {
497+ < Badge status = { isDraft ? 'info' : 'success' } >
498+ { isDraft ? 'Draft' : 'Active' }
499+ </ Badge >
500+ }
501+ secondaryActions = { [
502+ { content : 'Duplicate' } ,
503+ { content : 'View on your store' } ,
504+ ] }
505+ pagination = { {
506+ hasPrevious : true ,
507+ hasNext : true ,
508+ } }
509+ >
510+ < LegacyCard sectioned >
511+ < FormLayout >
512+ < TextField
513+ autoComplete = "off"
514+ label = "Title"
515+ value = { title }
516+ onChange = { handleChange ( 'title' ) }
517+ />
518+ < TextField
519+ multiline
520+ autoComplete = "off"
521+ label = "Description"
522+ value = { description }
523+ onChange = { handleChange ( 'description' ) }
524+ />
525+ </ FormLayout >
526+ </ LegacyCard >
527+ </ Page >
528+ </ Frame >
529+ ) ;
530+ }
0 commit comments